<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
    <head>
        <!-- Book generated using mdBook -->
        <meta charset="UTF-8">
        <title>The Rust Rand Book</title>
        
        <meta name="robots" content="noindex" />
        
        


        <!-- Custom HTML head -->
        


        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="Extended documentation for Rust&#x27;s Rand lib">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="theme-color" content="#ffffff" />

        
        <link rel="icon" href="favicon.svg">
        
        
        <link rel="shortcut icon" href="favicon.png">
        
        <link rel="stylesheet" href="css/variables.css">
        <link rel="stylesheet" href="css/general.css">
        <link rel="stylesheet" href="css/chrome.css">
        <link rel="stylesheet" href="css/print.css" media="print">

        <!-- Fonts -->
        <link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
        
        <link rel="stylesheet" href="fonts/fonts.css">
        

        <!-- Highlight.js Stylesheets -->
        <link rel="stylesheet" href="highlight.css">
        <link rel="stylesheet" href="tomorrow-night.css">
        <link rel="stylesheet" href="ayu-highlight.css">

        <!-- Custom theme stylesheets -->
        

        
    </head>
    <body>
        <!-- Provide site root to javascript -->
        <script type="text/javascript">
            var path_to_root = "";
            var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
        </script>

        <!-- Work around some values being stored in localStorage wrapped in quotes -->
        <script type="text/javascript">
            try {
                var theme = localStorage.getItem('mdbook-theme');
                var sidebar = localStorage.getItem('mdbook-sidebar');

                if (theme.startsWith('"') && theme.endsWith('"')) {
                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
                }

                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
                }
            } catch (e) { }
        </script>

        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme;
            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
            if (theme === null || theme === undefined) { theme = default_theme; }
            var html = document.querySelector('html');
            html.classList.remove('no-js')
            html.classList.remove('light')
            html.classList.add(theme);
            html.classList.add('js');
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var html = document.querySelector('html');
            var sidebar = 'hidden';
            if (document.body.clientWidth >= 1080) {
                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
                sidebar = sidebar || 'visible';
            }
            html.classList.remove('sidebar-visible');
            html.classList.add("sidebar-" + sidebar);
        </script>

        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
            <div class="sidebar-scrollbox">
                <ol class="chapter"><li class="chapter-item expanded affix "><a href="intro.html">介绍</a></li><li class="chapter-item expanded "><a href="guide-start.html"><strong aria-hidden="true">1.</strong> 入门指南</a></li><li class="chapter-item expanded "><a href="crates.html"><strong aria-hidden="true">2.</strong> crate 和特性</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="crates-rand.html"><strong aria-hidden="true">2.1.</strong> 随机加密(co)</a></li><li class="chapter-item expanded "><a href="crates-gen.html"><strong aria-hidden="true">2.2.</strong> 随机信号生成器</a></li></ol></li><li class="chapter-item expanded "><a href="guide.html"><strong aria-hidden="true">3.</strong> 指南</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="guide-data.html"><strong aria-hidden="true">3.1.</strong> 随机数据</a></li><li class="chapter-item expanded "><a href="guide-gen.html"><strong aria-hidden="true">3.2.</strong> 生成器类型</a></li><li class="chapter-item expanded "><a href="guide-rngs.html"><strong aria-hidden="true">3.3.</strong> 随机数生成器(RNGs)</a></li><li class="chapter-item expanded "><a href="guide-seeding.html"><strong aria-hidden="true">3.4.</strong> 为随机数生成器置种</a></li><li class="chapter-item expanded "><a href="guide-values.html"><strong aria-hidden="true">3.5.</strong> 随机值</a></li><li class="chapter-item expanded "><a href="guide-dist.html"><strong aria-hidden="true">3.6.</strong> 各种分布方式</a></li><li class="chapter-item expanded "><a href="guide-seq.html"><strong aria-hidden="true">3.7.</strong> 序列</a></li><li class="chapter-item expanded "><a href="guide-err.html"><strong aria-hidden="true">3.8.</strong> 错误处理</a></li></ol></li><li class="chapter-item expanded "><a href="portability.html"><strong aria-hidden="true">4.</strong> 可移植性</a></li><li class="chapter-item expanded "><a href="update.html"><strong aria-hidden="true">5.</strong> 更新</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="update-0.5.html"><strong aria-hidden="true">5.1.</strong> 更新到 0.5</a></li><li class="chapter-item expanded "><a href="update-0.6.html"><strong aria-hidden="true">5.2.</strong> 更新到 0.6</a></li><li class="chapter-item expanded "><a href="update-0.7.html"><strong aria-hidden="true">5.3.</strong> 更新到 0.7</a></li></ol></li><li class="chapter-item expanded "><a href="contributing.html"><strong aria-hidden="true">6.</strong> 贡献</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="contrib-doc.html"><strong aria-hidden="true">6.1.</strong> 文档</a></li><li class="chapter-item expanded "><a href="contrib-scope.html"><strong aria-hidden="true">6.2.</strong> Scope</a></li><li class="chapter-item expanded "><a href="contrib-test.html"><strong aria-hidden="true">6.3.</strong> 测试</a></li><li class="chapter-item expanded "><a href="contrib-bench.html"><strong aria-hidden="true">6.4.</strong> 基准</a></li></ol></li></ol>
            </div>
            <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
        </nav>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                
                <div id="menu-bar-hover-placeholder"></div>
                <div id="menu-bar" class="menu-bar sticky bordered">
                    <div class="left-buttons">
                        <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                            <i class="fa fa-bars"></i>
                        </button>
                        <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                            <i class="fa fa-paint-brush"></i>
                        </button>
                        <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                            <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                        </ul>
                        
                        <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                            <i class="fa fa-search"></i>
                        </button>
                        
                    </div>

                    <h1 class="menu-title">The Rust Rand Book</h1>

                    <div class="right-buttons">
                        <a href="print.html" title="Print this book" aria-label="Print this book">
                            <i id="print-button" class="fa fa-print"></i>
                        </a>
                        
                    </div>
                </div>

                
                <div id="search-wrapper" class="hidden">
                    <form id="searchbar-outer" class="searchbar-outer">
                        <input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                    </form>
                    <div id="searchresults-outer" class="searchresults-outer hidden">
                        <div id="searchresults-header" class="searchresults-header"></div>
                        <ul id="searchresults">
                        </ul>
                    </div>
                </div>
                

                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
                <script type="text/javascript">
                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                    });
                </script>

                <div id="content" class="content">
                    <main>
                        <h1><a class="header" href="#the-rust-rand-book" id="the-rust-rand-book">The Rust Rand Book</a></h1>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/intro.md">intro.md</a><br />
commit: 09b9f3ba87c8ee7c0480aceaefce4028d01cf592 <br />
本章译文最后维护日期：2020-11-21</p>
</blockquote>
<p>这是 Rust随机数库的扩展文档。</p>
<p>本书包含：</p>
<ol>
<li><a href="guide-start.html">入门指南</a></li>
<li><a href="crates.html">crate 和相关功能</a>的概述</li>
<li><a href="crates.html">相关 crate 和相关功能</a>的概述</li>
<li><a href="guide.html">用户手册</a></li>
<li>关于[可移植性和可再现性(reproducibility)]的说明(portability.md)。（如果需要不同构建目标下的可重现性，请阅读本文）</li>
<li><a href="update.html">更新指南</a></li>
<li><a href="contributing.html">贡献指南</a></li>
</ol>
<p>在本书之外，您可能还希望了解：</p>
<ul>
<li><a href="https://docs.rs/rand/">最新版本的API参考</a></li>
<li><a href="../rand/">主分支的API参考</a></li>
<li><a href="https://github.com/rust-random/rand/">Rand 的源码仓库</a></li>
<li><a href="https://github.com/rust-random/book/">本书源码</a></li>
</ul>
<h1><a class="header" href="#getting-started" id="getting-started">Getting Started</a></h1>
<h1><a class="header" href="#入门指南" id="入门指南">入门指南</a></h1>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/guide-start.md">guide-start.md</a><br />
commit: 09b9f3ba87c8ee7c0480aceaefce4028d01cf592 <br />
本章译文最后维护日期：2020-11-21</p>
</blockquote>
<p>下面我们列举了一个简短的例子。更多信息，请参考<a href="https://rust-random.github.io/rand/rand/index.html">API文档</a>或<a href="guide.html">指南</a>。</p>
<p>让我们以一个例子开始（<a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=4cad6600b21578cfa22009c281c780fe">playground链接</a>）：</p>
<pre><pre class="playground"><code class="language-rust editable"><span class="boring">extern crate rand;
</span>// 从预导入包(prelude)中导入常用的程序项(items)：
use rand::prelude::*;

fn main() {
    // 我们可以直接使用 random()。它可以生成许多常见类型的值。
    let x: u8 = random();
    println!(&quot;{}&quot;, x);

    if random() { // 产生一个布尔值
        println!(&quot;Heads!&quot;);
    }

    // 如果我们想要更明确一点（也更有效率一点），我们可以为线程级随机生成器(thread-local generator)创建一个句柄：
    let mut rng = thread_rng();
    if rng.gen() { // 布尔随机
        let x: f64 = rng.gen(); // 在区间[0, 1)之间浮点随机数
        let y = rng.gen_range(-10.0, 10.0);
        println!(&quot;x is: {}&quot;, x);
        println!(&quot;y is: {}&quot;, y);
        println!(&quot;Number from 0 to 9: {}&quot;, rng.gen_range(0, 10));
    }
    
    // 有时直接使用某个分布方式(distribution)也很有用：
    let distr = rand::distributions::Uniform::new_inclusive(1, 100);
    let mut nums = [0i32; 3];
    for x in &amp;mut nums {
        *x = rng.sample(distr);
    }
    println!(&quot;Some numbers: {:?}&quot;, nums);
    
    // 我们还可以用它来和迭代器或切片交互：
    let arrows_iter = &quot;➡⬈⬆⬉⬅⬋⬇⬊&quot;.chars();
    println!(&quot;Lets go in this direction: {}&quot;, arrows_iter.choose(&amp;mut rng).unwrap());
    let mut nums = [1, 2, 3, 4, 5];
    nums.shuffle(&amp;mut rng);
    println!(&quot;I shuffled my {:?}&quot;, nums);
}
</code></pre></pre>
<p>你可能注意到的第一件事是我们从<a href="https://rust-random.github.io/rand/rand/prelude/index.html">预导入包(prelude)</a>中导入了所有的程序项。这是 <code>use</code> rand 的一个偷懒的方式，这个就跟<a href="https://doc.rust-lang.org/std/prelude/index.html">标准库的预导入包</a>一样，只导入最常用的程序项。
如果不想使用预导入包(prelude)，那请记住导入 <a href="https://rust-random.github.io/rand/rand/trait.Rng.html"><code>Rng</code></a> trait!</p>
<p>Rand库可以根据需要自动初始化一个安全的线程级随机生成器。这可以通过函数 <a href="https://rust-random.github.io/rand/rand/fn.thread_rng.html"><code>thread_rng</code></a> 和 <a href="https://rust-random.github.io/rand/rand/fn.random.html"><code>random</code></a> 来访问。
有关这个主题的更多信息，请参见<a href="guide-gen.html">随机生成器</a>。</p>
<p>虽然函数 <a href="https://rust-random.github.io/rand/rand/fn.random.html"><code>random</code></a> 只能以<a href="https://rust-random.github.io/rand/rand/distributions/struct.Standard.html"><code>Standard</code></a>（典型依赖）的方式获取抽样值(sample values)，但 <a href="https://rust-random.github.io/rand/rand/fn.thread_rng.html"><code>thread_rng</code></a> 可以给你一个生成器的句柄。
所有生成器都实现了 <a href="https://rust-random.github.io/rand/rand/trait.Rng.html"><code>Rng</code></a> trait，它们都提供了上面示例中使用的 <a href="https://rust-random.github.io/rand/rand/trait.Rng.html#method.gen"><code>gen</code></a>、<a href="https://rust-random.github.io/rand/rand/trait.Rng.html#method.gen_range"><code>gen_range</code></a> 和 <a href="https://rust-random.github.io/rand/rand/trait.Rng.html#method.sample"><code>sample</code></a> 这些方法。</p>
<p>Rand还通过 <a href="https://rust-random.github.io/rand/rand/seq/trait.IteratorRandom.html"><code>IteratorRandom</code></a> 和 <a href="https://rust-random.github.io/rand/rand/seq/trait.SliceRandom.html"><code>SliceRandom</code></a> 这两个额外的 trait 提供了针对迭代器和切片的函数。</p>
<h2><a class="header" href="#fixed-seed-rngs" id="fixed-seed-rngs">Fixed seed RNGs</a></h2>
<h2><a class="header" href="#固定种子随机数生成器" id="固定种子随机数生成器">固定种子随机数生成器</a></h2>
<p>您可能已经注意到在上面示例中 <code>thread_rng()</code> 的使用，想知道如何指定固定的随机数种子。
为此，需要先指定一个RNG(随机数生成器)，然后使用像 <a href="https://rust-random.github.io/rand/rand/trait.SeedableRng.html#method.seed_from_u64"><code>seed_from_u64</code></a> 或<a href="https://rust-random.github.io/rand/rand/trait.SeedableRng.html#tymethod.from_seed"><code>from_seed</code></a> 这样的方法。</p>
<p>注意 <a href="https://rust-random.github.io/rand/rand/trait.SeedableRng.html#method.seed_from_u64"><code>seed_from_u64</code></a> <strong>不适合用于加密</strong>，因为单个 <code>u64</code> 不能提供足够的熵来安全地为RNG置种(seeding)。
所有用于加密的RNG都是通过 <a href="https://rust-random.github.io/rand/rand/trait.SeedableRng.html#tymethod.from_seed"><code>from_seed</code></a> 来接收更合适的随机数种子的。</p>
<p>下面我们使用了 <code>ChaCha8Rng</code>，因为它速度快，可移植性好，质量也好。
更多RNG请参阅 <a href="guide-rngs.html">RNGs</a> 部分，但是如果您关心可重现的结果，请避免使用 <code>SmallRng</code> 和 <code>StdRng</code>。</p>
<pre><pre class="playground"><code class="language-rust editable">extern crate rand;
extern crate rand_chacha;

use rand::{Rng, SeedableRng};

fn main() {
    let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(10);
    println!(&quot;Random f32: {}&quot;, rng.gen::&lt;f32&gt;());
}
</code></pre></pre>
<h1><a class="header" href="#crates-and-features" id="crates-and-features">Crates and features</a></h1>
<h1><a class="header" href="#crates-和特性" id="crates-和特性">Crates 和特性</a></h1>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/crates.md">crates.md</a><br />
commit: 137d3179243735851dd1e73d154c671195881bd0 <br />
本章译文最后维护日期：2020-11-21</p>
</blockquote>
<p>Rand库由一组 crate 组成。其中 <a href="https://rust-random.github.io/rand/rand/index.html"><code>rand</code></a> crate 提供了主用户接口；如果需要其他的分布方式(distribution)，<a href="https://rust-random.github.io/rand/rand_distr/index.html"><code>rand_distr</code></a> 或 <a href="https://github.com/boxtown/statrs"><code>statrs</code></a> crate 可能会被派上用场。</p>
<p>这个库包含几个构建块：<a href="https://docs.rs/getrandom/"><code>getrandom</code></a> 与平台相关的随机数源接口，<a href="https://rust-random.github.io/rand/rand_core/index.html"><code>rand_core</code></a> 定义了生成器必须实现的API，而像 <a href="https://rust-random.github.io/rand/rand_chacha/index.html"><code>rand_chacha</code></a> 和 <a href="https://rust-random.github.io/rand/rand_xoshiro/index.html"><code>rand_xoshiro</code></a> 这类 crates 提供了多种伪随机信号生成器。</p>
<pre><code>getrandom ┐
          └ rand_core ┐
                      ├ rand_chacha ┐
                      ├ rand_hc     ┤
                      ├ rand_pcg    ┤
                      └─────────────┴ rand ┐
                                           ├ rand_distr
                                           └ statrs
</code></pre>
<h2><a class="header" href="#feature-flags" id="feature-flags">Feature flags</a></h2>
<h2><a class="header" href="#特性标志位" id="特性标志位">特性标志位</a></h2>
<p>Rand crate 允许通过特性标志位进行配置。请检查每个 crate 的 README文件以了解详情。</p>
<p>通过禁用默认特性：<code>rand = { version = &quot;0.7&quot;, default-features = false }</code>，大多数 Rand crate 都提供了对 no-std 模式支持。
但此特性的关闭还会受到以下标志位的影响：</p>
<!-- tobecheck -->
<ul>
<li><code>std</code> 选择依赖于 <code>std</code>库的相关函数</li>
<li><code>alloc</code>（启用 <code>std</code>模式会默认开启此特性）支持需要分配器(allocator)的函数（如果在 <code>no_std</code>模式中使用此特性时，Rand 需要 Rustc 1.36 或更高的版本）</li>
</ul>
<p>一些 Rand crate 可以支持以下第三方 crate：</p>
<ul>
<li><code>log</code> 允许通过 <a href="https://docs.rs/log/"><code>log</code></a> 记录一些日志消息</li>
<li><code>serde1</code> 支持通过1.0版的 <a href="https://serde.rs/"><code>serde</code></a> 来启用序列化数据对象</li>
</ul>
<p>请注意，加密型RNG<em>不</em>支持序列化，因为这可能存在安全风险。如果需要加密型RNG上的状态恢复功能，ChaCha生成器支持<a href="https://rust-random.github.io/rand/rand_chacha/struct.ChaCha20Rng.html#method.get_word_pos">获取并设置流位置</a>，它与随机种子(seed)一起使用可重建生成器的状态。<!-- tobocheck --></p>
<h2><a class="header" href="#wasm-support" id="wasm-support">WASM support</a></h2>
<h2><a class="header" href="#支持wasm" id="支持wasm">支持WASM</a></h2>
<p>几乎所有的 Rand crate 都是开箱即用的。只有 <code>rand_core</code> crate 在<a href="https://github.com/rust-random/getrandom#features">支持WASM功能时需要启用相关特性</a>。
因此，如果使用的是另一个依赖于 <code>rand_core</code> 的 crate（如大多数的 Rand crates），就必须显式地启用 <code>getrandom</code>特性才能正常工作。</p>
<h1><a class="header" href="#rand-and-co" id="rand-and-co">Rand and co</a></h1>
<h1><a class="header" href="#随机和加密" id="随机和加密">随机和加密</a></h1>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/crates-rand.md">crates-rand.md</a><br />
commit: c5de1dc9ba6f5852023432fea3f988da7bfecefc <br />
本章译文最后维护日期：2020-11-21</p>
</blockquote>
<h2><a class="header" href="#rand_core-api" id="rand_core-api">rand_core (API)</a></h2>
<p><a href="https://rust-random.github.io/rand/rand_core/index.html"><code>rand_core</code></a> crate 定义了RNG需要实现的核心trait。把它分割为一个单独的 crate 有两个目的：</p>
<ul>
<li>为定义和使用RNG提供最小的API</li>
<li>提供工具来协助实现各类RNG</li>
</ul>
<p><a href="https://rust-random.github.io/rand/rand_core/trait.RngCore.html"><code>RngCore</code></a>、<a href="https://rust-random.github.io/rand/rand_core/trait.SeedableRng.html"><code>SeedableRng</code></a>、<a href="https://rust-random.github.io/rand/rand_core/trait.CryptoRng.html"><code>CryptoRng</code></a> 这些 trait 以及类型 <a href="https://rust-random.github.io/rand/rand_core/struct.Error.html"><code>Error</code></a> 都是在这个 crate 里定义的，并由 <a href="https://rust-random.github.io/rand/rand/index.html"><code>rand</code></a> crate 重新导出。</p>
<h2><a class="header" href="#rand-primary-interface" id="rand-primary-interface">rand (primary interface)</a></h2>
<h2><a class="header" href="#rand主接口" id="rand主接口">rand（主接口）</a></h2>
<p><a href="https://rust-random.github.io/rand/rand/index.html"><code>rand</code></a> crate 为便于使用常见的随机数功能做了优化。表现在这几个层面：</p>
<ul>
<li>模块 <a href="https://rust-random.github.io/rand/rand/rngs/index.html"><code>rngs</code></a> 提供了几个方便使用的生成器</li>
<li>模块 <a href="https://rust-random.github.io/rand/rand/distributions/index.html"><code>distributions</code></a> 涉及随机值的抽样</li>
<li>模块 <a href="https://rust-random.github.io/rand/rand/seq/index.html"><code>seq</code></a> 涉及对序列进行抽样和重排(shuffling)</li>
<li><a href="https://rust-random.github.io/rand/rand/trait.Rng.html"><code>Rng</code></a> trait 提供了一些生成随机值的便利方法</li>
<li>函数 <a href="https://rust-random.github.io/rand/rand/fn.random.html"><code>random</code></a> 为单次调用提供了便利</li>
</ul>
<h3><a class="header" href="#feature-flags-1" id="feature-flags-1">Feature flags</a></h3>
<h2><a class="header" href="#特性标志位-1" id="特性标志位-1">特性标志位</a></h2>
<p>除了<a href="crates.html#feature-flags">常用特性标志位</a>之外，还有几个地方是可配置的：</p>
<ul>
<li>标志位 <code>small_rng</code> 可以启用 <a href="https://rust-random.github.io/rand/rand/rngs/struct.SmallRng.html"><code>SmallRng</code></a>生成器（该特性选通功能从 v0.7 开始可用）</li>
<li><code>simd_support</code> 启用生成SIMD值的实验性（目前仅限 nightly版可用）支持</li>
</ul>
<p>关于SIMD的提示：上面的标志位只涉及SIMD类型的显式生成，而不是优化。SIMD操作可以在内部使用，而不去考虑这个标志位；比如 ChaCha生成器在内部就对SIMD操作有明确的支持。</p>
<h2><a class="header" href="#distributions" id="distributions">Distributions</a></h2>
<h2><a class="header" href="#分布方式distribution" id="分布方式distribution">分布方式(distribution)</a></h2>
<p><a href="https://rust-random.github.io/rand/rand/index.html"><code>rand</code></a> crate 只执行最常见的随机数分布抽样：均匀抽样(uniform sampling)和加权抽样(weighted sampling)。其他情况下，以下可用：</p>
<ul>
<li><a href="https://rust-random.github.io/rand/rand_distr/index.html"><code>rand_distr</code></a> 提供了从其他各种分布的快速采样，包括正态（高斯）分布、二项分布、泊松分布、单位圆分布等等</li>
<li><a href="https://github.com/boxtown/statrs"><code>statrs</code></a> 是对 C# 的 Math.NET库的一个模仿，它比照着实现了许多相同的分布方式(distribution)（加/减几个），以及PDF和CDF函数、<em>error</em>、<em>beta</em>、<em>gamma</em> 和 <em>logistic</em> 这些特殊函数，再加上一些实用工具。（澄清一点，<a href="https://github.com/boxtown/statrs"><code>statrs</code></a>不是 Rand库的一部分，它是一个独立的项目。）</li>
</ul>
<h1><a class="header" href="#random-generators" id="random-generators">Random Generators</a></h1>
<h1><a class="header" href="#随机信号生成器" id="随机信号生成器">随机信号生成器</a></h1>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/crates-gen.md">crates-gen.md</a><br />
commit: c5de1dc9ba6f5852023432fea3f988da7bfecefc <br />
本章译文最后维护日期：2020-11-21</p>
</blockquote>
<h2><a class="header" href="#getrandom" id="getrandom">Getrandom</a></h2>
<p><a href="https://github.com/rust-random/getrandom"><code>getrandom</code></a> crate 提供了一个围绕特定于平台的随机数源的低级API，是 <code>rand</code> 和 <code>rand_core</code> 以及许多加密库的重要构建块。
它的目的是在低级库内部使用。</p>
<p>在某些情况下，特别是以WASM为编译目标时，终端用户可能需要对这个 crate 做一些配置。
具体版本要求请参阅 <a href="https://github.com/rust-random/getrandom"><code>getrandom</code></a> 文档。</p>
<h2><a class="header" href="#cpu-jitter" id="cpu-jitter">CPU Jitter</a></h2>
<h2><a class="header" href="#cpu-jittercpu抖动" id="cpu-jittercpu抖动">CPU Jitter(CPU抖动)</a></h2>
<p><a href="https://rust-random.github.io/rand/rand_jitter/index.html"><code>rand_jitter</code></a> crate 实现了基于CPU抖动的熵采集器(CPU-jitter-based entropy harvestor)，此采集器在高精度CPU计时器可用的情况下可用于（为随即生成器）提供替代熵源。</p>
<p>值得注意的是，CPU抖动采集器(CPU-jitter harvestors)<a href="https://github.com/rust-random/rand/issues/699">可能容易受到侧信道攻击(side-channel attacks)</a>，而且这种实现非常慢（由于对每一步获得的熵的保守估计）。<!-- tobocheck --></p>
<p>在 <code>rand</code> 的前期版本中，这是一个直接依赖关系，当其他熵源失败时会自动使用此熵源。
在当前版本中，它不再是依赖项（甚至不再是一个可选项）。</p>
<h2><a class="header" href="#deterministic-generators" id="deterministic-generators">Deterministic generators</a></h2>
<h2><a class="header" href="#确定性随机信号生成器" id="确定性随机信号生成器">确定性随机信号生成器</a></h2>
<p>下面的 crates 实现了伪随机数生成器(pseudo-random number generators)（参见<a href="guide-rngs.html">随机数生成器</a>）：</p>
<ul>
<li><a href="https://rust-random.github.io/rand/rand_chacha/index.html"><code>rand_chacha</code></a> 提供了使用 ChaCha密码的随机数生成器</li>
<li><a href="https://rust-random.github.io/rand/rand_hc/index.html"><code>rand_hc</code></a> 使用 HC-128密码实现的随机数生成器</li>
<li><a href="https://rust-random.github.io/rand/rand_isaac/index.html"><code>rand_isaac</code></a> 实现ISAAC随机数生成器</li>
<li><a href="https://rust-random.github.io/rand/rand_pcg/index.html"><code>rand_pcg</code></a> 部分实现PCG的随机数生成器</li>
<li><a href="https://rust-random.github.io/rand/rand_xoshiro/index.html"><code>rand_xoshiro</code></a>实现了 SplitMix算法和 Xoshiro算法的随机数生成器</li>
<li><a href="https://rust-random.github.io/rand/rand_xorshift/index.html"><code>rand_xorshift</code></a>实现了基础Xorshift算法的随机数生成器</li>
</ul>
<h1><a class="header" href="#guide" id="guide">Guide</a></h1>
<h1><a class="header" href="#指南" id="指南">指南</a></h1>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/guide.md">guide.md</a><br />
commit: 09b9f3ba87c8ee7c0480aceaefce4028d01cf592 <br />
本章译文最后维护日期：2020-11-21</p>
</blockquote>
<p>本节试图解释这个库中使用的一些概念。</p>
<ol>
<li><a href="guide-data.html">什么是随机数据，而什么又是随机性(randomness)？</a></li>
<li><a href="guide-gen.html">有哪些种类的随机信号生成器？</a></li>
<li><a href="guide-rngs.html">Rand 提供了什么样的随机数生成器？</a></li>
<li><a href="guide-values.html">将随机数据转换为有用的值</a></li>
<li><a href="guide-dist.html">分布方式(distribution)：精细控制随机值</a></li>
<li><a href="guide-seq.html">序列</a></li>
<li><a href="guide-err.html">错误处理</a></li>
</ol>
<h2><a class="header" href="#importing-items-prelude" id="importing-items-prelude">Importing items (prelude)</a></h2>
<h2><a class="header" href="#导入程序项预导入包" id="导入程序项预导入包">导入程序项（预导入包）</a></h2>
<p>从 Rand 中导入程序项最方便的方法是使用导入程序项 <a href="https://rust-random.github.io/rand/rand/prelude/index.html"><code>prelude</code></a>。
预导入包虽然包含了 Rand 最主要的部分，但只包括那些不太可能引起名称冲突的部分。</p>
<p>注意，相比于以前的版本，Rand 0.5 显著地改变了模块的组织和内容。可能的旧名称还被保留着（但是隐藏在文档中），但是这些将在将来被删除。因此，在老数据迁移时，我们建议在导入中使用预导入包(prelude)或使用新的模块组织。</p>
<h2><a class="header" href="#further-examples" id="further-examples">Further examples</a></h2>
<h2><a class="header" href="#更多示例" id="更多示例">更多示例</a></h2>
<p>要获得更多启发，请参阅以下示例程序：</p>
<ul>
<li><a href="https://github.com/rust-random/rand/blob/master/examples/monte-carlo.rs">π的蒙特卡罗估算(Monte Carlo estimation)</a></li>
<li><a href="https://github.com/rust-random/rand/blob/master/examples/monty-hall.rs">蒙提霍尔问题(Monty Hall Problem)</a></li>
</ul>
<h1><a class="header" href="#random-data" id="random-data">Random data</a></h1>
<h1><a class="header" href="#随机数据" id="随机数据">随机数据</a></h1>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/guide-data.md">guide-data.md</a><br />
commit: 37f01c4663f960a5af1546d2173afe0e64bf9b2c <br />
本章译文最后维护日期：2020-11-21</p>
</blockquote>
<pre><pre class="playground"><code class="language-rust">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">extern crate rand;
</span><span class="boring">use rand::RngCore;
</span>// get some random data:
let mut data = [0u8; 32];
rand::thread_rng().fill_bytes(&amp;mut data);
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#what-is-randomness" id="what-is-randomness">What is randomness?</a></h2>
<h2><a class="header" href="#什么是随机性" id="什么是随机性">什么是随机性？</a></h2>
<p>**随机(random)**是什么意思？通俗来说，这个词可以简单地表示 <em>意外</em> 或 <em>未知</em>，但我们需要更精确一些。这里维基百科给了我们一个更具体的定义：</p>
<blockquote>
<p>**随机性(randomness)**是指事件缺乏模式或可预测性。</p>
</blockquote>
<p>我们可以更进一步：“缺乏模式”意味着没有“偏差(bias)”；换句话说，所有的值都是等可能的(equally likely)。</p>
<p>为了理解什么是<em>随机值</em>，我们仍然需要上下文：我们的随机值可以来自哪个数字池？</p>
<ul>
<li>举个简单的例子，考虑骰子：它们的值为1、2、3、4、5 和 6，一个无偏（公平）的骰子会使每个数字等可能发生，概率均为 ⅙ 。</li>
<li>现在我们举一个愚蠢的例子：自然数（1，2，3，...）。这些数字没有上限。所以，如果要求一个无偏的随机自然数，那 1，5，1000，100万，1万亿 - 所有这些数字的可能性都是一样的。然而事实上，对于<em>任何</em>自然数 <code>k</code>，数字区间 <code>1, 2, ..., k</code> 是所有自然数的无穷小部分，这意味着从该区间中选择一个无偏数的概率实际上是 <code>1/∞ = 0</code>。而另一方面，对于<em>任何</em>自然数，我们期望的无偏随机值概率都比实际概率（0）要大（否则取不出来）。（实际无偏概率为0，而又要取出无偏随机自然数，）这是不可能的，所以不可能存在任何无偏随机自然数。</li>
<li>另一个例子：0 到 1 之间的实数。实数包括所有的分数，无理数，如 π 和 √2，以及所有这些数的倍数...。实数的可能性是无穷多的，即使是像在 <code>(0, 1)</code> 这样一个很小的区间内，所以仅仅简单地说“所有可能性都是等可能的”是不够的。这里我们换一种方式来解释“缺乏模式”：每个大小相等的区间都是等可能的；例如，我们可以将区间 <code>0,1</code> 细分为 <code>0,½</code> 和 <code>½,1</code>，然后掷硬币来决定随机样本来自哪个区间。假设我们选择 <code>½,1</code>，然后再掷另一枚硬币，在 <code>½,¾</code> 和 <code>¾,1</code> 之间进行选择，将随机值限制在原区间的 <code>¼</code> 大小的区间内。我们可以根据需要重复多次，以尽可能精确地在 <code>0</code> 和 <code>1</code> 之间选择一个随机值，尽管我们需要意识到，我们选择的不是<em>精确</em>值，而是一个很小的区间。</li>
</ul>
<p>上面我们定义（或未能定义）的是均匀随机数分布，或者简单地说是<strong>均匀分布(uniform distributions)</strong>。还有一些非均匀分布，我们将在后面看到。同样值得注意的是，均匀分布并不意味着其样本会均匀分布（试试掷六个骰子：你可能得不到 1、2、3、4、5、6）。</p>
<p>为了让计算成为可能，我们现在可以在以下几种上下文中定义均匀分布的随机值（无偏随机值）是什么：</p>
<ul>
<li><code>u32</code>：介于 0 到 <code>u32::MAX</code> 之间的随机数，其中的每个值出现的可能性相等</li>
<li><code>BigInt</code>：由于此类型没有上限，因此无法生成无偏随机值（它会无限的大，并使用无限量的内存）</li>
<li><code>f64</code>：我们将其视为实数的近似值，并且，<em>按照惯例</em>，限制在 0 到 1 的区间内（如果没有另外指定）。这里涉及到转换方式(conversion)，我们在后面用到转换方式时会进一步深入此话题；现在请注意，这些转换会产生 52-53 bits 的精度（根据使用的转换方式，输出将以 <code>ε</code> 或 <code>ε/2</code> 为步长，其中 <code>1+ε</code> 是大于 <code>1</code> 的最小可表示值）。</li>
</ul>
<h2><a class="header" href="#random-data-1" id="random-data-1">Random data</a></h2>
<h2><a class="header" href="#随机数据-1" id="随机数据-1">随机数据</a></h2>
<p>如上所示，如果没有上下文，“随机数”这个词是没有意义的。“随机数据”通常意味着一个随机<em>字节</em>序列，其中对于每个字节，256 个可能值中的每一个都是等可能的。</p>
<p><a href="https://rust-random.github.io/rand/rand_core/trait.RngCore.html#tymethod.fill_bytes"><code>RngCore::fill_bytes</code></a> 生成的正是这个：一个随机字节序列。</p>
<p>如果正确长度的无偏随机字节序列被解释为整数（比如 <code>u32</code> 或 <code>u64</code>），则结果就是无偏整数。由于这种转换方式很常用，所以 <a href="https://rust-random.github.io/rand/rand_core/trait.RngCore.html#tymethod.next_u32"><code>RngCore::next_u32</code></a> 和 <a href="https://rust-random.github.io/rand/rand_core/trait.RngCore.html#tymethod.next_u64"><code>RngCore::next_u64</code></a> 就在同一 trait 中声明了。（事实上，这种转换方式通常是相反的 - 各种算法生成器通常先在内部处理整数，然后将整数转换为所需的任意形式的随机数据。）</p>
<h1><a class="header" href="#types-of-generators" id="types-of-generators">Types of generators</a></h1>
<h1><a class="header" href="#生成器类型" id="生成器类型">生成器类型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/guide-gen.md">guide-gen.md</a><br />
commit: c5de1dc9ba6f5852023432fea3f988da7bfecefc <br />
本章译文最后维护日期：2020-11-22</p>
</blockquote>
<p>上一节介绍了 <a href="https://rust-random.github.io/rand/rand_core/trait.RngCore.html"><code>RngCore</code></a>，它是所有*随机数据源(random data sources)*必须实现的 trait。但随机数据源到底又是什么？</p>
<p>本节主要涉及理论；要进一步了解这些理论也可参见<a href="guide-rngs.html">随机数生成器(RNGs)</a>这一章。</p>
<pre><pre class="playground"><code class="language-rust">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">extern crate rand;
</span><span class="boring">extern crate rand_pcg;
</span>// 准备一个非确定性随机数生成器：
let mut rng = rand::thread_rng();

// 准备一个确定性随机数生成器：
use rand::SeedableRng;
let mut rng = rand_pcg::Pcg32::seed_from_u64(123);
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#true-random-number-generators" id="true-random-number-generators">True random number generators</a></h2>
<h2><a class="header" href="#真随机数生成器" id="真随机数生成器">真随机数生成器</a></h2>
<p><strong>真</strong>随机数生成器（TRNG）是通过观察某些自然过程（如原子衰变或热噪声）而生成随机数的程序装置。（不管这些东西是否<em>真的</em>是随机的，还是事实上是确定性的——例如，如果我们的宇宙本身就是一个模拟——这是不重要的。就我们的目的而言，它们与真正的随机性没有区别就足够了。）</p>
<p>请注意，这些过程通常是有偏的，因此必须使用某种类型的*去偏(debiasing)*方法来生成我们想要的无偏随机数据。</p>
<h2><a class="header" href="#pseudo-random-number-generators" id="pseudo-random-number-generators">Pseudo-random number generators</a></h2>
<h2><a class="header" href="#伪随机数产生器" id="伪随机数产生器">伪随机数产生器</a></h2>
<p>各类CPU当然都应该进行确定性的计算，但事实证明它们在模拟随机过程方面做得也很好。大多数伪随机数生成器都是确定性的，可以仅用以下条件来定义：</p>
<ul>
<li>设定一些初始<em>状态(state)</em></li>
<li>从状态中计算随机值的函数</li>
<li>前进到下一状态的函数</li>
<li>（可选）一个从*种子(seed)<em>或</em>键(key)*派生出初始状态的函数</li>
</ul>
<p>事实上，确定性有时是非常有用的：它允许一个模拟的、随机性的艺术创作或游戏被精确地重复，并产生一个输入种子的函数映射结果。关于这方面的更多信息，请参阅<a href="portability.html">可移植性</a>一章（注意，仅确定性不足以保证再现性）。</p>
<p>各种PRNG的另一大吸引力在于其速度：其中一些算法对每个随机值只需要少量CPU操作，因此可以比大多数TRNG更快地按需生成随机数据。</p>
<p>但是请注意，PRNG有几个限制：</p>
<ul>
<li>它们的（安全性或随机性）并不比它们的种子强：如果种子是已知的或是可猜测的，并且算法是已知的（或可猜测的），那么可能只有有限可能的输出序列。</li>
<li>由于状态的尺寸(size)通常是固定的，所以在重新进入生成器循环迭代之前，只有有限数量的输出值是可能的。</li>
<li>有一些算法在观察一些结果值后很容易预测这些算法的机理，而其他更多算法则不清楚它们将来是否会被“破解”。</li>
</ul>
<h2><a class="header" href="#cryptographically-secure-pseudo-random-number-generator" id="cryptographically-secure-pseudo-random-number-generator">Cryptographically secure pseudo-random number generator</a></h2>
<h2><a class="header" href="#密码学安全伪随机数生成器" id="密码学安全伪随机数生成器">密码学安全伪随机数生成器</a></h2>
<p>密码学安全伪随机数生成器（CSPRNG）是伪随机数生成器的子集，它被认为安全的。即：</p>
<ul>
<li>它们的状态的尺寸足够大，因此简单地尝试所有初始值的暴力方法不是找到用于产生观察到的输出值序列的初始状态的可行方法，</li>
<li>并且没有其他算法比暴力方法更好地来预测下一个输出值。</li>
</ul>
<p>实现安全生成不仅需要安全算法（CSPRNG），还需要安全且足够大的种子值（通常为256位），以及防止侧信道攻击（即防止攻击者读取内部状态）</p>
<p>一些CSPRNG还满足第三条属性：</p>
<ul>
<li>禁止回溯。也就是在攻击者发现了当前算法的内部状态的情况下，他也无法计算PRNG的先前输出值（当然这意味着所有未来输出都不再安全了）。</li>
</ul>
<h2><a class="header" href="#hardware-random-number-generator" id="hardware-random-number-generator">Hardware random number generator</a></h2>
<h2><a class="header" href="#硬件随机数生成器" id="硬件随机数生成器">硬件随机数生成器</a></h2>
<p>一个<strong>硬件</strong>随机数生成器（HRNG）理论上是从TRNG到数字信号的适配器。在实践中，可能还要使用PRNG来为TRNG去偏。即使HRNG是一种潜在的TRNG，但也不能保证它是安全的：TRNG本身可能产生不充分的熵（即太可预测），或者信号放大和去噪过程可能有缺陷。</p>
<p>HRNG可用于为PRNG提供种子，尽管这通常不是获得安全种子的唯一方法（请参阅下一节）。HRNG可能会完全取代PRNG，但由于我们现在拥有非常快速和强大的软件PRNG，并且由于软件实现比硬件实现更容易验证，因此这通常不是首选的解决方案。</p>
<p>由于PRNG需要一个随机的种子值来保证安全，所以可以使用HRNG来提供该种子，甚至可以替代PRNG。然而，由于目标通常是“仅”生成不可预测的随机值，因此也有一些可接受的替代方法来代替<em>真</em>随机数生成器（请参阅下一节）。</p>
<h2><a class="header" href="#entropy" id="entropy">Entropy</a></h2>
<h2><a class="header" href="#熵" id="熵">熵</a></h2>
<p>如上所述，要保证CSPRNG的安全，它的种子值也必须是安全的，因此要关注熵。“熵”这个词有两种用法：</p>
<ul>
<li>作为某种数据中未知信息量的度量</li>
<li>作为一段未知的数据</li>
</ul>
<p>理想情况下，一个随机布尔值或一个硬币掷硬币有1-bit的熵，尽管如果这个值是偏置的，还会有更少的熵。香农熵试图测量这一点。</p>
<p>例如，Unix时间戳（自1970年开始以来的秒数）既包含高精度数据，也包含低精度数据。它通常是一个32-bit的数字，但是<em>熵</em>的大小将取决于假想的攻击者能够准确地猜出这个数字。如果攻击者能猜到最接近的那一分钟，那么这个数字可能是大约6-bit（2^6=64）；如果攻击者能猜到秒，那熵就是0-bit。<a href="https://rust-random.github.io/rand/rand/rngs/jitter/struct.JitterRng.html"><code>JitterRng</code></a> 使用这个概念在没有HRNG参与的情况下清除熵（但是使用纳秒精度的计时器，并且保守地假设在对计时器的质量进行了几次测试之后，每个时间戳只有几个比特的熵可用）。</p>
<h1><a class="header" href="#our-rngs" id="our-rngs">Our RNGs</a></h1>
<h1><a class="header" href="#随机数生成器" id="随机数生成器">随机数生成器</a></h1>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/guide-gen.md">guide-gen.md</a><br />
commit: c5de1dc9ba6f5852023432fea3f988da7bfecefc <br />
本章译文最后维护日期：2020-11-28</p>
</blockquote>
<p>RNG有很多种，各有不同的取舍。Rand 在 <a href="https://rust-random.github.io/rand/rand/rngs/index.html"><code>rngs</code>模块</a>中提供了一些方便趁手的生成器。一般情况下只使用 <a href="https://rust-random.github.io/rand/rand/fn.thread_rng.html"><code>thread_rng</code></a> 就可以了，这个函数会在线程的局部内存中自动初始化一个RNG，并返回一个RNG的引用。它速度快，质量好，而且（据我们所知）加密安全。</p>
<p>本节内容：</p>
<ol>
<li><a href="guide-rngs.html#the-generators">生成器</a></li>
<li><a href="guide-rngs.html#performance">性能和尺寸(size)</a></li>
<li><a href="guide-rngs.html#quality">Quality and cycle length</a></li>
<li><a href="guide-rngs.html#security">安全性</a></li>
<li><a href="guide-rngs.html#extra-features">额外功能</a></li>
<li><a href="guide-rngs.html#further-reading">延伸阅读</a></li>
</ol>
<h1><a class="header" href="#the-generators" id="the-generators">The generators</a></h1>
<h1><a class="header" href="#生成器" id="生成器">生成器</a></h1>
<h2><a class="header" href="#basic-pseudo-random-number-generators-prngs" id="basic-pseudo-random-number-generators-prngs">Basic pseudo-random number generators (PRNGs)</a></h2>
<h2><a class="header" href="#初级伪随机数生成器" id="初级伪随机数生成器">初级伪随机数生成器</a></h2>
<p>“标准”非加密型PRNG的目标通常是在简单性、质量、内存使用和性能之间找到一个良好的平衡。非加密生成器比加密生成器出现的早，并且在某些方面已经被加密生成器淘汰，不过，非加密生成器也有一些优势：状态范围小、初始化快、简单、可使用低功耗的嵌入式CPU。（然而，并非所有的非加密型PRNG都提供了这些好处，例如，尽管很容易预测，但梅森旋转(Mersenne Twister/MT)算法的状态却非常大）。</p>
<p>这些（初级伪随机）算法对蒙特卡洛模拟(Monte Carlo simulations)非常重要；这些算法也适用于随机算法和游戏中，这些场景下的可预测性不是核心问题。（注意，对于赌博游戏，可预测性可能是一个问题，建议使用加密型PRNG。）</p>
<p>Rand项目提供了几个非加密型PRNG。
下面总结了其中的一些。详情可以参考 <a href="http://www.pcg-random.org/">pcg-random</a> 和 <a href="http://xoshiro.di.unimi.it/">xoshiro</a> 网站。</p>
<table><thead><tr><th>名称</th><th>全称</th><th>性能表现</th><th>占用内存</th><th>质量评价</th><th>周期长度</th><th>特性</th></tr></thead><tbody>
<tr><td><a href="https://rust-random.github.io/rand/rand/rngs/struct.SmallRng.html"><code>SmallRng</code></a></td><td>(未指定)</td><td>7 GB/s</td><td>16 字节</td><td>★★★☆☆</td><td>≥ <code>u32</code> * 2<sup>64</sup></td><td>不能被移植</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_pcg/type.Pcg32.html"><code>Pcg32</code></a></td><td>PCG XSH RR 64/32 (LCG)</td><td>3 GB/s</td><td>16 字节</td><td>★★★☆☆</td><td><code>u32</code> * 2<sup>64</sup></td><td>—</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_pcg/type.Pcg64.html"><code>Pcg64</code></a></td><td>PCG XSL 128/64 (LCG)</td><td>4 GB/s</td><td>32 字节</td><td>★★★☆☆</td><td><code>u64</code> * 2<sup>128</sup></td><td>—</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_pcg/type.Pcg64Mcg.html"><code>Pcg64Mcg</code></a></td><td>PCG XSL 128/64 (MCG)</td><td>7 GB/s</td><td>16 字节</td><td>★★★☆☆</td><td><code>u64</code> * 2<sup>126</sup></td><td>—</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_xorshift/struct.XorShiftRng.html"><code>XorShiftRng</code></a></td><td>Xorshift 32/128</td><td>5 GB/s</td><td>16 字节</td><td>★☆☆☆☆</td><td><code>u32</code> * 2<sup>128</sup> - 1</td><td>—</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_xoshiro/struct.Xoshiro256PlusPlus.html"><code>Xoshiro256PlusPlus</code></a></td><td>Xoshiro256++</td><td>7 GB/s</td><td>32 字节</td><td>★★★☆☆</td><td><code>u64</code> * 2<sup>256</sup> - 1</td><td>jump-ahead</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_xoshiro/struct.Xoshiro256Plus.html"><code>Xoshiro256Plus</code></a></td><td>Xoshiro256+</td><td>8 GB/s</td><td>32 字节</td><td>★★☆☆☆</td><td><code>u64</code> * 2<sup>256</sup> - 1</td><td>jump-ahead</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_xoshiro/struct.SplitMix64.html"><code>SplitMix64</code></a></td><td>splitmix64</td><td>8 GB/s</td><td>8 字节</td><td>★☆☆☆☆</td><td><code>u64</code> * 2<sup>64</sup></td><td>—</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand/rngs/mock/struct.StepRng.html"><code>StepRng</code></a></td><td>counter</td><td>51 GB/s</td><td>16 字节</td><td>☆☆☆☆☆</td><td><code>u64</code> * 2<sup>64</sup></td><td>—</td></tr>
</tbody></table>
<p>这里基于 3.4GHz Haswell CPU，粗略地测量了 <code>u64</code>类型的输出的性能（请注意，这可能因具体测试的应用而有较大的结果差异；通常加密型RNG使用字节序列输出效果更好）。质量评价基于内部算法和可观察到的缺陷，大致如下：</p>
<ul>
<li>★☆☆☆☆ = 适合简单的应用程序，但有明显的缺陷</li>
<li>★★☆☆☆ = 在大多数测试中表现良好，存在一些问题</li>
<li>★★★☆☆ = 良好的性能和算法，没有重大问题</li>
<li>★★★★★ = 加密级质量(cryptographic quality)</li>
</ul>
<h2><a class="header" href="#cryptographically-secure-pseudo-random-number-generators-csprngs" id="cryptographically-secure-pseudo-random-number-generators-csprngs">Cryptographically secure pseudo-random number generators (CSPRNGs)</a></h2>
<h2><a class="header" href="#加密安全伪随机数生成器csprng" id="加密安全伪随机数生成器csprng">加密安全伪随机数生成器(CSPRNG)</a></h2>
<p>CSPRNG比初级PRNG要求要高。首要考虑的是安全性。性能和简洁性也很重要，但通常CSPRNG比常规PRNG更复杂、更慢。对CSPRNG来说，质量评级不再是一个问题，因为CSPRNG的要求是输出基本上与真正的随机性没有区别，因为任何偏差或相关性都可能使输出更具有可预测性。</p>
<p>CSPRNG与密码学有着密切的关系。通过对计数器进行加密，任何分组密码都可以转换为CSPRNG。流密码基本上是一个CSPRNG和一个组合操作，通常是异或。这意味着我们可以很容易地将任何流密码用作CSPRNG。</p>
<p>这个库提供了以下CSPRNG。我们不能保证任何安全要求。由于CSPRNG可能没有可观察到的缺陷，此表省略了前表中的“质量评价”列。</p>
<table><thead><tr><th>名称</th><th>全称</th><th>性能</th><th>初始化速度</th><th>占用内存</th><th>安全性 (可预测性)</th><th>前向安全性(forward secrecy)</th></tr></thead><tbody>
<tr><td><a href="https://rust-random.github.io/rand/rand/rngs/struct.StdRng.html"><code>StdRng</code></a></td><td>(未指定)</td><td>1.5 GB/s</td><td>快</td><td>136 字节</td><td>广受信任</td><td>无</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_chacha/struct.ChaCha20Rng.html"><code>ChaCha20Rng</code></a></td><td>ChaCha20</td><td>1.8 GB/s</td><td>快</td><td>136 字节</td><td><a href="https://tools.ietf.org/html/rfc7539#section-1">严格分析</a></td><td>无</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_chacha/struct.ChaCha8Rng.html"><code>ChaCha8Rng</code></a></td><td>ChaCha8</td><td>2.2 GB/s</td><td>快</td><td>136 字节</td><td>安全边际较小</td><td>无</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_hc/struct.Hc128Rng.html"><code>Hc128Rng</code></a></td><td>HC-128</td><td>2.1 GB/s</td><td>慢</td><td>4176 字节</td><td><a href="http://www.ecrypt.eu.org/stream/">eSTREAM推荐</a></td><td>无</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_isaac/isaac/struct.IsaacRng.html"><code>IsaacRng</code></a></td><td>ISAAC</td><td>1.1 GB/s</td><td>慢</td><td>2072 字节</td><td><a href="https://burtleburtle.net/bob/rand/isaacafa.html">未知</a></td><td>未知</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_isaac/isaac64/struct.Isaac64Rng.html"><code>Isaac64Rng</code></a></td><td>ISAAC-64</td><td>2.2 GB/s</td><td>慢</td><td>4136 字节</td><td>未知</td><td>未知</td></tr>
</tbody></table>
<p>需要指出的是，ISAAC生成器只是出于历史原因才被包括在内的，它们从一开始就使用了 Rust语言。它们具有高质量的输出，并且没有已知的攻击，但是它们很少受到加密专家的关注。</p>
<h1><a class="header" href="#notes-on-generators" id="notes-on-generators">Notes on generators</a></h1>
<h1><a class="header" href="#各种生成器的关注点" id="各种生成器的关注点">各种生成器的关注点</a></h1>
<h2><a class="header" href="#performance" id="performance">Performance</a></h2>
<h2><a class="header" href="#性能" id="性能">性能</a></h2>
<p>首先，必须说大多数PRNG都非常快，很少会成为性能瓶颈。</p>
<p>初级PRNG的性能有点微妙。它很大程度上取决于CPU架构（32bit vs. 64bit）、内联以及可用寄存器的数量。由于内联和其他寄存器的使用，这通常会导致性能还受到其周围代码的影响。</p>
<p>在考虑为性能而选择PRNG时需要注意，由于PRNG与其周围代码之间的交互作用、对CPU架构的依赖以及请求的数据大小的影响，那对自己的应用程序进行基准测试就显得非常重要。正因为如此，我们在这里不包括性能数字，而只是一个定性评级。</p>
<p>CSPRNGs略有不同，因为它们通常在缓存中生成一个输出块，并从缓存中提取输出。这使得它们具有良好的缓冲性能，并减少或完全消除了周围代码对其性能的影响。</p>
<h3><a class="header" href="#worst-case-performance" id="worst-case-performance">Worst-case performance</a></h3>
<h3><a class="header" href="#最坏情况下的性能" id="最坏情况下的性能">最坏情况下的性能</a></h3>
<p>简单的PRNG通常根据需要生成每个随机值。相比之下，CSPRNG通常一次生成整个块，然后从缓存中读取，直到缓存读完，这使得它们在提取少量随机数据时性能不太一致。</p>
<h3><a class="header" href="#memory-usage" id="memory-usage">Memory usage</a></h3>
<h3><a class="header" href="#内存使用量" id="内存使用量">内存使用量</a></h3>
<p>简单的PRNG通常使用很少的内存，通常只有几个字(word)，其中<em>字</em>通常是 <code>u32</code> 或 <code>u64</code>。但并非所有非加密型PRNG都是如此，例如历史上流行的Mersenne Twister MT19937算法需要 2.5 kB 的状态。</p>
<p>CSPRNG通常需要更多的内存；由于建议种子大小至少为192-bit，而且算法可能需要更多的 bit，256-bit大概是最小的安全大小。在实际实践中，CSPRNG往往使用更多，<a href="https://rust-random.github.io/rand/rand_chacha/struct.ChaChaRng.html"><code>ChaChaRng</code></a> 的内存使用量相对较小，只有 136个字节的状态。</p>
<h3><a class="header" href="#initialization-time" id="initialization-time">Initialization time</a></h3>
<h3><a class="header" href="#初始化时间" id="初始化时间">初始化时间</a></h3>
<p>初始化新生成器所需的时间差别很大。许多简单PRNG，甚至一些CSPRNG（包括 <a href="https://rust-random.github.io/rand/rand_chacha/struct.ChaChaRng.html"><code>ChaChaRng</code></a>）只需要将种子值和一些常量复制进它们的状态里，就可以很快地构造出来。相比之下，具有大状态的CSPRNG则需要昂贵的密钥扩展。</p>
<h2><a class="header" href="#quality" id="quality">Quality</a></h2>
<h2><a class="header" href="#质量评价" id="质量评价">质量评价</a></h2>
<p>许多初级PRNG只不过是一些位运算和算术运算。它们的简单性提供了良好的性能，但也意味着在生成的随机数流中隐藏了一些小的规律。</p>
<p>这些隐藏的规律有多大的负作用？这很难说，取决于如何使用RNG。如果随机数和使用它们的算法之间碰巧存在相关性，结果可能是错误的或误导性的。</p>
<p>如果一个随机数生成器能在尽可能多的应用中给出正确的结果，那么它就可以被认为是好的。
PRNG算法的质量可以在一定程度上进行分析评估，以确定循环长度(cycle length)，并排除一些相关性。此外，还有一些经验测试套件，旨在测试PRNG在各种可能用途上的表现，其中最新和最完整的是 <a href="http://simul.iro.umontreal.ca/testu01/tu01.html">TestU01</a> 和 <a href="http://pracrand.sourceforge.net/">PractRand</a>。</p>
<p>CSPRNG往往更复杂，并且有一个明确的要求是不可预测的。这意味着各个输出值之间一定没有明显的相关性。</p>
<h3><a class="header" href="#quality-stars" id="quality-stars">Quality stars:</a></h3>
<h3><a class="header" href="#质量评星等级" id="质量评星等级">质量评星等级</a></h3>
<p>对于大多数非加密应用，3星或更高的PRNG应该足够好了。对于典型的应用程序和游戏来说，1星或 2星可能已经足够了，但并不所有的算法在所有的场景下都能很好的运行。</p>
<h3><a class="header" href="#period" id="period">Period</a></h3>
<h3><a class="header" href="#周期" id="周期">周期</a></h3>
<p>PRNG的<em>周期</em>或*循环长度(cycle length)*是可以生成的值的数目，之后它开始重复相同的随机数流。许多PRNG都有一个固定的大小周期，而对于另一些（“混沌随机数生成器”），其周期长度可能取决于种子，并且允许存在短周期。</p>
<p>注意，长周期并不意味着高质量（例如，通过 <code>u128</code> 值的计数器提供了相当长的周期）。当然，短周期也可能是一个问题，特别是在同时使用多个RNG时。
一般来说，我们建议周期至少为 2<sup>128</sup>。（或者，一个至少为 2<sup>64</sup> 的较短周期，并且支持多个流的PRNG可能就足够了。但请注意，在PCG的情况下，其流是密切相关的。）<!-- tobocheck --></p>
<p><em>避免重用值！</em>
在今天的硬件上，一个循环长度虽然<em>只有</em> 2<sup>64</sup> 的快速RNG仍然可以在一个循环用尽之前连续使用几个世纪。但是，当多个RNG并行使用时（每个rng都有一个唯一的种子），它们生成的输出序列之间有很大的几率会重叠。
对于具有<em>大</em>周期 <code>P</code> 的 <code>n</code>个独立生成器，并且每个生成器生成的序列的长度为 <code>L</code>，当 <code>nL / P</code> 接近于零时，序列之间的任何重叠概率可以近似为 <code>Ln² / P</code> 。有关这个主题的更多信息，请参见 <a href="http://prng.di.unimi.it/#remarks">Xoshiro的作者的这些评论</a>。</p>
<p><em>碰撞和生日悖论!</em>
对于输出与状态相等的生成器，建议不要使用超过 <code>√P</code> 的输出。对<code>kw</code>-bit 长度的状态和 <code>w</code>-bit 长度的生成器的总的原则是确保 <code>kL² &lt; P</code>。这一要求源于<em>广义生日问题</em>，即在重复发生的概率至少为一半之前，从一组大小为 <code>d = 2^w</code> 的样本集合中可以提取多少个无偏样本。
注意，对于 <code>kL² &gt; P</code> ，具有 <code>kw</code>维等分布的生成器<em>不能</em>生成预期的重复样本数，但是没有此属性的生成器<em>也</em>不能保证生成预期的重复样本数。</p>
<h2><a class="header" href="#security" id="security">Security</a></h2>
<h2><a class="header" href="#安全性" id="安全性">安全性</a></h2>
<h3><a class="header" href="#predictability" id="predictability">Predictability</a></h3>
<h3><a class="header" href="#可预测性" id="可预测性">可预测性</a></h3>
<p>从任何PRNG的上下文中，可以提出这样的问题*给出PRNG之前的一些输出，是否有可能预测下一个输出值？*在任何可能有攻击者的情况下，这是一个重要的问题。</p>
<p>常规的PRNG往往是可预测的，尽管困难程度各不相同。在某些情况下，预测不要太容易哦，例如简单的 Xorshift算法会不加任何修改的输出其状态的一部分，对它们的预测就像从四个 <code>u32</code> 输出中植入一个新的Xorshift生成器一样简单。其他生成器，如<a href="http://www.pcg-random.org/predictability.html">PCG</a>和 截断Xorshift算法 要难预测一些，但也不超出普通数学和台式机的运算能力范围之外。</p>
<p>CSPRNG必须提供的基本安全要求是预测输出的不可行性。这一要求被形式化为<a href="https://en.wikipedia.org/wiki/Next-bit_test">下一位测试(next-bit test)</a>；这可大致描述为：给定随机序列的前 <em>k</em>位，如果没有算法能够使用合理的计算能力预测下一位，则序列满足下一位测试。</p>
<p><em>一些</em>CSPRNG提供了另一种安全性是前向保密:在CSPRNG的状态在某些时候被泄露的情况下，重建之前的状态或输出是不可行的。注意，许多CSPRNG在其通常的配置中<em>没有</em>实现前向保密。</p>
<p>验证算法的安全性声明是一个<em>困难的问题</em>，所以我们无法为本项目使用或推荐的算法的安全性提供任何保证。我们建议您向<a href="https://www.nist.gov/">NIST</a>研究所和<a href="http://www.ecrypt.eu.org/">ECRYPT</a>网络寻求建议。</p>
<h3><a class="header" href="#state-and-seeding" id="state-and-seeding">State and seeding</a></h3>
<h3><a class="header" href="#设定状态和种子" id="设定状态和种子">设定状态和种子</a></h3>
<p>值得注意的是，CSPRNG的安全性完全依赖于使用一个安全的随机密钥来置种(seeding)。如果密钥是已知的或可猜测的，CSPRNG的所有输出都很容易猜测。这意味着种子应该来自可信的源；通常是操作系统或另一个CSPRNG。我们用来置种(seeding)的辅助trait，<a href="https://rust-random.github.io/rand/rand/trait.FromEntropy.html"><code>FromEntropy</code></a>，及其使用的源（<a href="https://rust-random.github.io/rand/rand/rngs/struct.EntropyRng.html"><code>EntropyRng</code></a>）应该是安全的。此外，<a href="https://rust-random.github.io/rand/rand/rngs/struct.ThreadRng.html"><code>ThreadRng</code></a> 是一个CSPRNG，因此它可以用此 trait 来置种(seeding)（尽管对于安全应用程序，应该首选新鲜/外部熵来作文种子来源）。</p>
<p>此外，很明显，CSPRNG的内部状态必须保密。考虑到这一点，我们的实现不提供对其大多数内部状态的直接访问，<code>Debug</code>实现也不打印任何内部状态。这并不能完全保护CSPRNG的状态；同一进程中的代码可能会读取这个内存（为了方便起见，我们允许克隆和序列化CSPRNG）。再有，一个正在运行的进程可能被操作系统 fork，这样可能会给两个进程都留下同一个生成器的副本。</p>
<h3><a class="header" href="#not-a-crypto-library" id="not-a-crypto-library">Not a crypto library</a></h3>
<h3><a class="header" href="#注意-rand-不是一个密码学库" id="注意-rand-不是一个密码学库">注意 Rand 不是一个密码学库</a></h3>
<p>需要强调的是，Rand 不是一个密码学库；尽管 Rand 确实采取了一些措施来提供安全的随机数，但它没有全部采取密码学所推荐的所有措施。此外，加密和身份验证等加密过程非常复杂，必须非常小心地实现，以避免漏洞，和抵御已知的攻击。因此，建议专业项目尽可能使用专用的密码学库，例如 <a href="https://crates.io/crates/openssl">openssl</a>、<a href="https://crates.io/crates/ring">ring</a> 和 <a href="https://github.com/RustCrypto">RustCrypto库</a>。</p>
<h2><a class="header" href="#extra-features" id="extra-features">Extra features</a></h2>
<h2><a class="header" href="#额外功能" id="额外功能">额外功能</a></h2>
<p>有一些PRNG还提供了额外的功能</p>
<ul>
<li>支持多流来助力并行任务。</li>
<li>在随机数流中跳转或搜索的能力；在长周期的条件下，可以作为流的替代。</li>
</ul>
<h2><a class="header" href="#further-reading" id="further-reading">Further reading</a></h2>
<h2><a class="header" href="#延伸阅读" id="延伸阅读">延伸阅读</a></h2>
<p>关于PRNG的资料非常丰富。<a href="http://www.pcg-random.org/pdf/hmc-cs-2014-0905.pdf">PCG的论文</a>也大都很容易理解，其中也解释了更多的概念。</p>
<p>另一篇关于RNG的高质量论文是 P. Hellekalek 写的[“好的随机数生成器（不是那么）容易找到”]https://web.archive.org/web/20160801142711/http://random.mat.sbg.ac.at/results/peter/A19final.pdf)。</p>
<h1><a class="header" href="#seeding-rngs" id="seeding-rngs">Seeding RNGs</a></h1>
<h1><a class="header" href="#为png置种seeding" id="为png置种seeding">为PNG置种(seeding)</a></h1>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/guide-seeding.md">guide-seeding.md</a><br />
commit: 3a691b0591512642e84ebad4d24012a949111dec <br />
本章译文最后维护日期：2020-11-30</p>
</blockquote>
<p>如我们所见，伪随机数生成器(PRNG)的输出由其初始状态决定。</p>
<p>一些PRNG的定义指定了如何从一个密钥来生成其初始状态，一般情况下，为加密生成器，需要指定一串字节序列，而对于小型PRNG，通常仅指定一个单词。对于此类可以置种的生成器，我们同一用 <a href="https://rust-random.github.io/rand/rand_core/trait.SeedableRng.html"><code>SeedableRng</code></a> trait 来对其进行形式化处理。。</p>
<h2><a class="header" href="#the-seed-type" id="the-seed-type">The Seed type</a></h2>
<h2><a class="header" href="#种子类型" id="种子类型">种子类型</a></h2>
<p>我们要求所有可置种的RNG需定义一个满足 <code>AsMut&lt;[u8]&gt; + Default + Sized</code>（通常是一个固定 <code>N</code> 的 <code>[u8; N]</code>）的 <a href="https://rust-random.github.io/rand/rand_core/trait.SeedableRng.html#type.Seed"><code>Seed</code></a>类型。
对于非加密型PRNG，我们建议使用 <code>[u8; 12]</code> 或更大；对于加密型PRNG，建议使用 <code>[u8; 32]</code>。</p>
<p>可以通过应用 <a href="https://rust-random.github.io/rand/rand_core/trait.SeedableRng.html#tymethod.from_seed"><code>SeedableRng::from_seed</code></a> 来获得此类建议值，同时直接为PRNG置种。</p>
<h2><a class="header" href="#seeding-from-" id="seeding-from-">Seeding from ...</a></h2>
<h2><a class="header" href="#置种的来源类型" id="置种的来源类型">置种的来源类型...</a></h2>
<h3><a class="header" href="#fresh-entropy" id="fresh-entropy">Fresh entropy</a></h3>
<h3><a class="header" href="#新鲜熵" id="新鲜熵">新鲜熵</a></h3>
<p>使用 <a href="https://rust-random.github.io/rand/rand_core/trait.SeedableRng.html#method.from_entropy"><code>SeedableRng::from_entropy</code></a> 来获取新鲜的种子（直接来自操作系统）是很容易的事儿：</p>
<pre><pre class="playground"><code class="language-rust editable">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use rand::prelude::*;
use rand_chacha::ChaCha20Rng;

let rng = ChaCha20Rng::from_entropy();
<span class="boring">}
</span></code></pre></pre>
<p>请注意，这需要 <code>rand_core</code>模块启用 <code>getrandom</code>特性。</p>
<h3><a class="header" href="#another-rng" id="another-rng">Another RNG</a></h3>
<h3><a class="header" href="#其他的rng" id="其他的rng">其他的RNG</a></h3>
<p>一个常见的操作是使用一个RNG为另一个RNG提供种子。为此，我们为这种常见的操作提供了一种方便的方法：</p>
<pre><pre class="playground"><code class="language-rust editable">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use rand::prelude::*;
use rand_pcg::Pcg64;

let rng = Pcg64::from_rng(thread_rng());
<span class="boring">}
</span></code></pre></pre>
<p>另一种情况，假设您想保存一个密钥并在以后使用它。为此，你可能需要指定更明确一点：</p>
<pre><pre class="playground"><code class="language-rust editable">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use rand::prelude::*;
use rand_chacha::ChaCha8Rng;

let mut seed: &lt;ChaCha8Rng as SeedableRng&gt;::Seed = Default::default();
thread_rng().fill(&amp;mut seed);
let rng = ChaCha8Rng::from_seed(seed);
<span class="boring">}
</span></code></pre></pre>
<p><strong>必须警告</strong>：一些简单的PRNG，特别是 <a href="https://rust-random.github.io/rand/rand_xorshift/struct.XorShiftRng.html"><code>XorShiftRng</code></a> 使用同一类型的生成器来置种时表现得很糟糕（在这种情况下，Xorshift 会生成一个克隆）。对于加密型PRNG，这不是问题；但对于其他类型的PRNG，仍建议从不同类型的生成器来获取种子。一般情况下，<a href="https://rust-random.github.io/rand/rand_chacha/struct.ChaCha8Rng.html"><code>ChaCha8Rng</code></a> 是种子生成器的最佳选择（但是对于加密用途，更好的选择是通过12轮或更多次的变换）。</p>
<h3><a class="header" href="#a-simple-number" id="a-simple-number">A simple number</a></h3>
<h3><a class="header" href="#简单数字" id="简单数字">简单数字</a></h3>
<p>对于某些应用程序，特别是模拟程序，一般只需要一系列不同的、固定的随机数种子，例如1、2、3等。</p>
<p><a href="https://rust-random.github.io/rand/rand_core/trait.SeedableRng.html#method.seed_from_u64"><code>SeedableRng::seed_from_u64</code></a> 正是为这种用例来设计的。在内部，它使用一个简单的PRNG来补充输入的种子数字中的比特位，同时提供良好的 bit-avalance（所以尽管两个类似的数字输入，如0和1，仍被转换成了非常不同的种子和独立的RNG序列）。</p>
<pre><pre class="playground"><code class="language-rust editable">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use rand::prelude::*;
use rand_pcg::Pcg64;

let rng = Pcg64::seed_from_u64(2);
<span class="boring">}
</span></code></pre></pre>
<p>请注意，64-bit 或位宽更少的数字<strong>是不安全的</strong>，因此不应将其用于加密或赌博游戏等应用场景。</p>
<h3><a class="header" href="#a-string-or-any-hashable-data" id="a-string-or-any-hashable-data">A string, or any hashable data</a></h3>
<h3><a class="header" href="#字符串或哈希数据" id="字符串或哈希数据">字符串或哈希数据</a></h3>
<p>假设让用户输入一个字符串来作为随机数生成器的种子。理想情况下，字符串的所有部分都应该能影响生成器，并且只需对字符串进行很小的更改就可以产生完全独立的生成器序列。</p>
<p>这可以通过使用哈希函数将所有输入数据压缩为一个哈希值，然后使用该值作为生成器种子来实现。<a href="https://github.com/rust-random/seeder/"><code>rand_seeder</code></a> crate 就是为了这个目的而设计的。</p>
<pre><pre class="playground"><code class="language-rust editable">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use rand::prelude::*;
use rand_seeder::{Seeder, SipHasher};
use rand_pcg::Pcg64;

// 使用&quot;stripy zebra&quot;的哈希值生成一个Seeder，然后用这个Seeder生成一个SeedableRng类型的RNG。
// 本例生成了为rand_pcg::Pcg64类型的:
let rng: Pcg64 = Seeder::from(&quot;stripy zebra&quot;).make_rng();

// 如果我们想要过程更清晰明确，我们可以首先创建一个SipRng：
let hasher = SipHasher::from(&quot;a sailboat&quot;);
let mut hasher_rng = hasher.into_rng();
// （注意：hasher_rng是一个功能完备的RNG，可以直接使用。）

// 现在，我们使用hasher_rng创建一个种子：
let mut seed: &lt;Pcg64 as SeedableRng&gt;::Seed = Default::default();
hasher_rng.fill(&amp;mut seed);

// 然后从这个种子中创建RNG：
let rng = Pcg64::from_seed(seed);
<span class="boring">}
</span></code></pre></pre>
<p>请注意，<code>rand_seeder</code> 对于加密用法是<strong>不适合的</strong>。它不是<strong>密码哈希器</strong>，对于此类应用程序，必须使用密钥派生函数，如 Argon2。</p>
<h1><a class="header" href="#random-values" id="random-values">Random values</a></h1>
<h1><a class="header" href="#随机值" id="随机值">随机值</a></h1>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/guide-values.md">guide-values.md</a><br />
commit: 37f01c4663f960a5af1546d2173afe0e64bf9b2c <br />
本章译文最后维护日期：2020-11-30</p>
</blockquote>
<p>既然我们已经有了生成随机数据的方法，那么如何将其转换为我们想要的值类型呢？</p>
<p>我们的回答有些狡黠：我们需要知道我们想要的值的分布*区间(range)<em>和这个值的</em>分布(distribution)*类型（这部分是 <a href="guide-dist.html"><code>next</code></a> 所涉及的内容）。</p>
<h2><a class="header" href="#the-rng-trait" id="the-rng-trait">The <code>Rng</code> trait</a></h2>
<p>为了方便起见，所有生成器都自动实现了 <a href="https://rust-random.github.io/rand/rand/trait.Rng.html"><code>Rng</code></a> trait，此trait 提供了几种生成随机值的便捷方法。下面是几个用来产生均匀分布的值的便捷函数：</p>
<ul>
<li>
<p><a href="https://rust-random.github.io/rand/rand/trait.Rng.html#method.gen"><code>Rng::gen</code></a> 从适合该类型的区间中生成一个无偏的（均匀分布的）随机值。对于整数类型，这通常是完整的可表示区间（例如，从 <code>0u32</code> 到 <code>std::u32::MAX</code>），对于浮点数，这是在0到1之间，还支持一些其他类型，包括数组和元组。</p>
<p>这种方法是对 <a href="https://rust-random.github.io/rand/rand/distributions/struct.Standard.html"><code>Standard</code></a>分布的一个便捷的包装器，<a href="guide-dist.html#uniform-distributions">下节</a>将对此进行阐述。</p>
</li>
<li>
<p><a href="https://rust-random.github.io/rand/rand/trait.Rng.html#method.gen_range"><code>Rng::gen_range</code></a> 生成一个无偏随机值，其边界为下包上不包</p>
</li>
<li>
<p><a href="https://rust-random.github.io/rand/rand/trait.Rng.html#method.fill"><code>Rng::fill</code></a> 和 <a href="https://rust-random.github.io/rand/rand/trait.Rng.html#method.try_fill"><code>Rng::try_fill</code></a> 用于填充任意数量的字节或整型切片的优化函数</p>
</li>
</ul>
<p>此trait 还带有两个生成非均匀分布的布尔值的便捷函数：</p>
<ul>
<li><a href="https://rust-random.github.io/rand/rand/trait.Rng.html#method.gen_bool"><code>Rng::gen_bool</code></a> 生成给定概率的布尔值</li>
<li><a href="https://rust-random.github.io/rand/rand/trait.Rng.html#method.gen_ratio"><code>Rng::gen_ratio</code></a> 也能生成一个布尔值，它的概率参数是通过一个分数定义的</li>
</ul>
<p>最后，此trait 还有一个从任意分布来抽样的函数：</p>
<ul>
<li><a href="https://rust-random.github.io/rand/rand/trait.Rng.html#method.sample"><code>Rng::sample</code></a> 直接从一些<a href="guide-dist.html">分布</a>中抽取样本(指南-dist.md)</li>
</ul>
<p>示例：</p>
<pre><pre class="playground"><code class="language-rust">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">extern crate rand;
</span>use rand::Rng;
let mut rng = rand::thread_rng();

// 从整个i 32区间内返回一个无偏整数：
let i: i32 = rng.gen();

// 返回一个0到1之间均匀分布的值：
let x: f64 = rng.gen();

// 模拟掷骰子：
let roll = rng.gen_range(1, 7);
<span class="boring">}
</span></code></pre></pre>
<p>此外，<a href="https://rust-random.github.io/rand/rand/fn.random.htm"><code>random</code></a>函数是 <a href="https://rust-random.github.io/rand/rand/trait.Rng.html#method.gen"><code>Rng::gen</code></a> 在 <a href="https://rust-random.github.io/rand/rand/fn.thread_rng.html"><code>thread_rng</code></a> 上的快捷方式:</p>
<pre><pre class="playground"><code class="language-rust">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>if rand::random() {
    println!(&quot;we got lucky!&quot;);
}
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/guide-dist.md">guide-dist.md</a><br />
commit: 37f01c4663f960a5af1546d2173afe0e64bf9b2c <br />
本章译文最后维护日期：2020-12-1</p>
</blockquote>
<h1><a class="header" href="#random-distributions" id="random-distributions">Random distributions</a></h1>
<h1><a class="header" href="#随机分布" id="随机分布">随机分布</a></h1>
<p>为了在产生随机值时获得最大的灵活性，我们定义了 <a href="https://rust-random.github.io/rand/rand/distributions/trait.Distribution.html"><code>Distribution</code></a> trait:</p>
<pre><pre class="playground"><code class="language-rust">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// T类数据的生产者：
pub trait Distribution&lt;T&gt; {
    // 主函数：
    fn sample&lt;R: Rng + ?Sized&gt;(&amp;self, rng: &amp;mut R) -&gt; T;

    // 使用上面 sample函数的便捷函数：
    fn sample_iter&lt;R&gt;(self, rng: R) -&gt; DistIter&lt;Self, R, T&gt;
    where
        Self: Sized,
        R: Rng,
    { ... }
}
<span class="boring">}
</span></code></pre></pre>
<p>Rand 提供了许多不同的分布(distribution)的实现；我们在这里讨论了其中最常见的几种，要获得完整的细节，请参阅 <a href="https://rust-random.github.io/rand/rand/distributions/index.html"><code>distributions</code></a>模块和 <a href="https://rust-random.github.io/rand/rand_distr/index.html"><code>rand_distr</code></a> crate。</p>
<h1><a class="header" href="#uniform-distributions" id="uniform-distributions">Uniform distributions</a></h1>
<h1><a class="header" href="#均匀分布" id="均匀分布">均匀分布</a></h1>
<p>最直观的分布类型是我们已经讨论过的：一种没有模式的分布，即每个值或值的区间都是等可能的。这就是所谓的“均匀(uniform)”。</p>
<p>Rand 实际上有几个均匀分布变体版本，代表了不同的区间(rang):</p>
<ul>
<li><a href="https://rust-random.github.io/rand/rand/distributions/struct.Standard.html"><code>Standard</code></a> 不需要传入参数，只需要根据输出类型就能在整个类型区间内均匀抽样取值。<a href="https://rust-random.github.io/rand/rand/trait.Rng.html#method.gen"><code>Rng::gen</code></a> 提供了使用此分布的快捷路径。</li>
<li><a href="https://rust-random.github.io/rand/rand/distributions/struct.Uniform.html"><code>Uniform</code></a> 可以通过 <code>Uniform::new(low, high)</code>（包括<code>low</code>，不包括<code>high</code>）的形式来传入参数，或通过 <code>Uniform::new_inclusive(low, high)</code>（两者都包括）来传入参数，并在此范围内均匀抽样。
<a href="https://rust-random.github.io/rand/rand/trait.Rng.html#method.gen_range"><code>Rng::gen_range</code></a> 是在 <a href="https://rust-random.github.io/rand/rand/distributions/struct.Uniform.html#method.sample_single"><code>Uniform::sample_single</code></a> 上定义的一种便捷方法，针对单个样本的使用进行了优化。</li>
<li><a href="https://rust-random.github.io/rand/rand/distributions/struct.Alphanumeric.html"><code>Alphanumeric</code></a> 是在 <code>char</code> 值 <code>0-9A-Za-z</code> 上的均匀分布。</li>
<li><a href="https://rust-random.github.io/rand/rand/distributions/struct.Open01.html"><code>Open01</code></a> 和 <a href="https://rust-random.github.io/rand/rand/distributions/struct.OpenClosed01.html"><code>OpenClosed01</code></a> 为浮点类型提供了备用抽样区间（见下文）</li>
</ul>
<h2><a class="header" href="#uniform-sampling-by-type" id="uniform-sampling-by-type">Uniform sampling by type</a></h2>
<h2><a class="header" href="#按类型均匀抽样" id="按类型均匀抽样">按类型均匀抽样</a></h2>
<p>让我们通过类型来简单浏览一遍各种分布：</p>
<ul>
<li>
<p>对于 <code>bool</code>”，<a href="https://rust-random.github.io/rand/rand/distributions/struct.Standard.html"><code>Standard</code></a>分布以50%的概率对每个值进行抽样。</p>
</li>
<li>
<p>对于 <code>Option&lt;T&gt;</code>，<a href="https://rust-random.github.io/rand/rand/distributions/struct.Standard.html"><code>Standard</code></a>分布以50%的概率抽样 <code>None</code>，另外50%会根据其类型对 <code>Some(value)</code> 进行抽样。</p>
</li>
<li>
<p>对于整数（<code>u8</code> 到 <code>u128</code>、<code>usize</code> 和各类 <code>i*</code>类型），<a href="https://rust-random.github.io/rand/rand/distributions/struct.Standard.html"><code>Standard</code></a>分布从所有可能的值进行抽样，而 <a href="https://rust-random.github.io/rand/rand/distributions/struct.Uniform.html"><code>Uniform</code></a>分布则从入参的区间进行抽样。</p>
</li>
<li>
<p>对于 <code>NonZeroU8</code> 和其他“非零”类型，<a href="https://rust-random.github.io/rand/rand/distributions/struct.Standard.html"><code>Standard</code></a>分布从所有非零值中均匀抽样（拒绝方法）。</p>
</li>
<li>
<p>对于 <code>Wrapping&lt;T&gt;</code> 包装的整数类型，<a href="https://rust-random.github.io/rand/rand/distributions/struct.Standard.html"><code>Standard</code></a>分布的抽样效果跟针对此相应的整型类型效果一样。</p>
</li>
<li>
<p>对于浮点型（<code>f32</code>，<code>f64</code>）</p>
<ul>
<li><a href="https://rust-random.github.io/rand/rand/distributions/struct.Standard.html"><code>Standard</code></a>分布会在半开区间 <code>[0，1)</code> 内抽样，抽样值的精度为24或53bit（分别对应 <code>f32</code> 和 <code>f64</code>）</li>
<li><a href="https://rust-random.github.io/rand/rand/distributions/struct.OpenClosed01.html"><code>OpenClosed01</code></a>分布会在半开区间 <code>(0, 1]</code> 内抽样，抽样值的精度为24或53bit</li>
<li><a href="https://rust-random.github.io/rand/rand/distributions/struct.Open01.html"><code>Open01</code></a>分布会在开区间 <code>(0, 1)</code> 内抽样，抽样值的精度为23或52bit</li>
<li><a href="https://rust-random.github.io/rand/rand/distributions/struct.Uniform.html"><code>Uniform</code></a>分布会在给定的区间内抽样，抽样值的精度为23或52bit</li>
</ul>
</li>
<li>
<p>对于 <code>char</code>类型，<a href="https://rust-random.github.io/rand/rand/distributions/struct.Standard.html"><code>Standard</code></a>分布从所有可用的 Unicode代码点进行均匀抽样；其中许多值可能无法打印（取决于字体支持）。<a href="https://rust-random.github.io/rand/rand/distributions/struct.Alphanumeric.html"><code>Alphanumeric</code></a>分布只对 a-z、a-z 和 0-9 进行均匀抽样。</p>
</li>
<li>
<p>对于元组和数组，在支持的情况下，每个元素都按上述方式进行抽样。
<a href="https://rust-random.github.io/rand/rand/distributions/struct.Standard.html"><code>Standard</code></a>分布和 <a href="https://rust-random.github.io/rand/rand/distributions/struct.Uniform.html"><code>Uniform</code></a>分布都支持批量填充这类类型（元组最多12个元素；数组最多32个元素）。
这包括空元组<code>()</code>和空数组。</p>
</li>
<li>
<p>对于SIMD类型，<a href="https://rust-random.github.io/rand/rand/distributions/struct.Standard.html"><code>Standard</code></a>分布和<a href="https://rust-random.github.io/rand/rand/distributions/struct.Uniform.html"><code>Uniform</code></a>分布对每个元素进行抽样（对于后者，<code>low</code>和<code>high</code>参数<em>也</em>都必须是SIMD类型，以便能有效地同时从多个区间进行抽样）。开启SIMD功能是通过一个<a href="../features.html#simd-support">特性标志位</a>实现的。</p>
</li>
</ul>
<h1><a class="header" href="#non-uniform-distributions" id="non-uniform-distributions">Non-uniform distributions</a></h1>
<h1><a class="header" href="#非均匀分布" id="非均匀分布">非均匀分布</a></h1>
<p>非均匀分布可分为以下两类。一些离散性非均匀分布和所有的连续性非均匀分布目前已经从主要的 <a href="https://rust-random.github.io/rand/rand/index.html"><code>rand</code></a> crate 移动到一个专门的 <a href="https://rust-random.github.io/rand/rand_distr/index.html"><code>rand_distr</code></a> crate 下了。</p>
<h2><a class="header" href="#discrete-non-uniform-distributions" id="discrete-non-uniform-distributions">Discrete non-uniform distributions</a></h2>
<h2><a class="header" href="#离散的非均匀分布" id="离散的非均匀分布">离散的非均匀分布</a></h2>
<p>离散分布从布尔或整数类型上抽样。如上所述，可以均匀地对这些样本进行抽样，或者如下所述，通过非均匀分布进行抽样。</p>
<p>离散分布可能直接从一组离散值（如切片或 <code>enum</code>）中抽样。参见<a href="../guide-seq.html">序列</a>一章中与切片和迭代器类型相关的 trait。Rand 没有提供直接从 <code>enum</code> 中抽样的功能，但 <code>Option</code> 除外（见上文）。</p>
<h3><a class="header" href="#booleans" id="booleans">Booleans</a></h3>
<p><a href="https://rust-random.github.io/rand/rand/distributions/struct.Bernoulli.html"><code>Bernoulli</code></a>分布是一个奇特的名称，用于生成布尔值，其中生成 <code>true</code> 的概率为给定的 <code>p</code>，或者通过比率 <code>success : failure</code> 来定义布尔值的生成比例。这通常用于描述一个<em>成功</em>（<code>true</code>）概率为 <code>p</code> 的<em>试验</em>。</p>
<p>方法<a href="https://rust-random.github.io/rand/rand/trait.Rng.html#method.gen_bool"><code>Rng::gen_bool</code></a>和<a href="https://rust-random.github.io/rand/rand/trait.Rng.html#method.gen_ratio"><code>Rng::gen_ratio</code></a> 是此分布的快捷方式。</p>
<h3><a class="header" href="#integers" id="integers">Integers</a></h3>
<p><a href="https://rust-random.github.io/rand/rand/distributions/struct.Binomial.html"><code>Binomial</code></a>分布与<a href="https://rust-random.github.io/rand/rand/distributions/struct.Bernoulli.html"><code>Bernoulli</code></a>分布有关，因为它模拟了n个独立的试验，每个试验都有成功的概率 <code>p</code>，然后计算成功的次数。</p>
<p>注意，对于较大的 <code>n</code>，['Binomial']分布的实现要比分 <code>n</code>次单独去抽样的试验快很多。</p>
<p><a href="https://rust-random.github.io/rand/rand/distributions/struct.Poisson.html"><code>Poisson</code></a>分布表示在一个固定的时间间隔内发生的事件的预期数量，并假定事件发生的速率为固定的 λ。</p>
<h3><a class="header" href="#weighted-sequences" id="weighted-sequences">Weighted sequences</a></h3>
<h3><a class="header" href="#加权序列" id="加权序列">加权序列</a></h3>
<p><a href="https://rust-random.github.io/rand/rand/distributions/weighted/struct.WeightedIndex.html"><code>WeightedIndex</code></a>分布从权重序列中抽取索引。请参阅<a href="../guide-seq.html">序列</a>章节来了解如何方便地使用包装器直接对切片元素进行采样。</p>
<p>例如，加权抽样可以用于对从一个装有5个绿色、15个红色和80个蓝色弹珠的桶中取样弹珠的颜色的过程进行建模。</p>
<p>目前，Rand库仅实现了<em>带替换的抽样(sampling with replacement)</em>，即假设在相同的初始分布中进行重复抽样（即任何被取走的弹球都被重新放回）。现在已经有一个要求实现*无替换的抽样(sampling without replacement)*分布的<a href="https://github.com/rust-random/rand/issues/596">需求</a>在开发中了。</p>
<p>还要注意 <a href="https://rust-random.github.io/rand/rand/distributions/weighted/struct.WeightedIndex.html"><code>WeightedIndex</code></a> 有两个实现可用；第一个为抽取少量的样本做了相应的优化，而 <a href="https://rust-random.github.io/rand/rand/distributions/weighted/alias_method/struct.WeightedIndex.html"><code>alias_method::WeightedIndex</code></a> 则为抽取大量的样本做了优化（其中的“大”可能意味着“&gt; 1000”；标准推荐）。</p>
<h2><a class="header" href="#continuous-non-uniform-distributions" id="continuous-non-uniform-distributions">Continuous non-uniform distributions</a></h2>
<h2><a class="header" href="#连续性非均匀分布" id="连续性非均匀分布">连续性非均匀分布</a></h2>
<p>连续分布模型样本取自实数线ℝ，在某些情况下也从更高维度（ℝ²、ℝ³等）提取样本。我们在大多数情况下为 <code>f64</code> 和 <code>f32</code>类型的输出提供了连续分布的实现，注意目前 <code>f32</code> 的实现只是降低了 <code>f64</code> 示例的精度。</p>
<p>指数分布 <a href="https://rust-random.github.io/rand/rand/distributions/struct.Exp.html"><code>Exp</code></a> 可以模拟衰减过程，假设衰减率固定（即指数衰减）。</p>
<p><a href="https://rust-random.github.io/rand/rand/distributions/struct.Normal.html"><code>Normal</code></a>分布（也称为高斯分布）用给定的平均值和标准差模拟正态分布（“钟形曲线”）的抽样。<a href="https://rust-random.github.io/rand/rand/distributions/struct.LogNormal.html"><code>LogNormal</code></a>是相关的：对于来自对数正态分布的样本 <code>X</code>，<code>log(X)</code> 是正态分布；这“扭曲”了正态分布，以避免出现负值，并带有一个长的正尾。</p>
<p><a href="https://rust-random.github.io/rand/rand/distributions/struct.UnitCircle.html"><code>UnitCircle</code></a>分布和 <a href="https://rust-random.github.io/rand/rand/distributions/struct.UnitSphereSurface.html"><code>UnitSphereSurface</code></a>分布模拟从圆的边缘或从球面上均匀采样。</p>
<p>['Cauchy']分布（也称为洛伦兹(Lorentz)分布）是角度均匀分布的从点 <code>(x0, γ)</code> 出发的射线相对于x轴的截距的分布。</p>
<p><a href="https://rust-random.github.io/rand/rand/distributions/struct.Beta.html"><code>Beta</code></a>分布是一个双参数概率分布，其输出值在0到1之间。<a href="https://rust-random.github.io/rand/rand/distributions/struct.Dirichlet.html"><code>Dirichlet</code></a>分布是对任何正数个参数的推广。</p>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/guide-seq.md">guide-seq.md</a><br />
commit: 13ffed85de51e6e4852c40823f7b7bf17b548520 <br />
本章译文最后维护日期：2020-12-1</p>
</blockquote>
<h1><a class="header" href="#sequences" id="sequences">Sequences</a></h1>
<h1><a class="header" href="#序列" id="序列">序列</a></h1>
<p>Rand 通过 <a href="https://rust-random.github.io/rand/rand/seq/trait.IteratorRandom.html"><code>IteratorRandom</code></a> 和 <a href="https://rust-random.github.io/rand/rand/seq/trait.SliceRandom.html"><code>SliceRandom</code></a> 这两个 trait 对序列执行一些常见的随机操作：</p>
<ul>
<li><code>choose</code> 用来从序列中均匀选择一个元素</li>
<li><code>choose_multiple</code> 用来从序列中均匀地无替换地选择多个元素。</li>
<li><code>choose_weighted</code> — 使用切片中定义的权重非均匀地选择元素（另请参见 <a href="https://rust-random.github.io/rand/rand/distributions/struct.WeightedIndex.html"><code>WeightedIndex</code></a>分布）</li>
<li><code>shuffle</code> 对切片内元素进行“洗牌”</li>
<li><code>partial_shuffle</code> 对切片进行部分洗牌，并有效地以随机顺序提取 <code>amount</code> 个元素</li>
</ul>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/guide-err.md">guide-err.md</a><br />
commit: 13ffed85de51e6e4852c40823f7b7bf17b548520 <br />
本章译文最后维护日期：2020-12-1</p>
</blockquote>
<h1><a class="header" href="#error-handling" id="error-handling">Error handling</a></h1>
<h1><a class="header" href="#错误处理" id="错误处理">错误处理</a></h1>
<p>Rand 中的错误处理在简单性和必要性之间做了折衷。大多数RNG和抽样函数永远不会产生错误，而让这些函数能够处理错误将增加巨大的开销（至少增加代码复杂度和增加不好的使用体验，可能还会降低性能，这取决于具体采用的方法）。
但是，外部RNG有可能会失败，因此对此进行处理是必要的且重要的。</p>
<p>因此，我们决定<em>大多数</em>方法不应该返回 <code>Result</code>类型，但也有一些比较重要的例外，也就是：</p>
<ul>
<li><a href="https://rust-random.github.io/rand/rand/trait.Rng.html#method.try_fill"><code>Rng::try_fill</code></a></li>
<li><a href="https://rust-random.github.io/rand/rand_core/trait.RngCore.html#tymethod.try_fill_bytes"><code>RngCore::try_fill_bytes</code></a></li>
<li><a href="https://rust-random.github.io/rand/rand_core/trait.SeedableRng.html#method.from_rng"><code>SeedableRng::from_rng</code></a></li>
</ul>
<p>大多数使用随机值的函数都不会尝试任何错误处理，因为它们基本上都是调用了 <a href="https://rust-random.github.io/rand/rand_core/trait.RngCore.html"><code>RngCore</code></a>里的那些“非常可靠”的方法。
由于大多数RNG不能失败，所以无论如何这通常都不是问题，但在下述情况下，少数生成器可以出现失败：</p>
<ul>
<li><a href="https://rust-random.github.io/rand/rand/rngs/struct.OsRng.html"><code>OsRng</code></a> 是与操作系统耦合的生成器；在极少数情况下，它可能会因为“未就绪”或只是“不可用”而失败。</li>
<li><a href="https://rust-random.github.io/rand/rand/rngs/struct.JitterRng.html"><code>JitterRng</code></a> 是一个基于计时器抖动的生成器；如果计时器似乎没有足够的精度或太可预测，则此过程将失败。</li>
<li><a href="https://rust-random.github.io/rand/rand/rngs/struct.EntropyRng.html"><code>EntropyRng</code></a> 是对前述内容的抽象，当其第一个选项失败时会执行下一个选项，但如果所有熵源都失败，则最终失败</li>
<li><a href="https://rust-random.github.io/rand/rand/fn.thread_rng.html"><code>thread_rng</code></a> 通过 <a href="https://rust-random.github.io/rand/rand/rngs/struct.EntropyRng.html"><code>EntropyRng</code></a> 为自己设置种子时，此时在每个线程上第一次使用会有可能失败（尽管在第一次使用之后它从未失败过）</li>
<li><a href="https://rust-random.github.io/rand/rand/rngs/adapter/struct.ReadRng.html"><code>ReadRng</code></a> 尝试从其源读取数据，但在流结束或出现错误时失败（尽管它在中断时会重试）。</li>
</ul>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/portability.md">portability.md</a><br />
commit: 2aaafc26d81b0df98c9af3edae8ab42fd9263c4e <br />
本章译文最后维护日期：2020-12-1</p>
</blockquote>
<h1><a class="header" href="#portability" id="portability">Portability</a></h1>
<h1><a class="header" href="#可移植性" id="可移植性">可移植性</a></h1>
<h2><a class="header" href="#definitions" id="definitions">Definitions</a></h2>
<h2><a class="header" href="#定义" id="定义">定义</a></h2>
<p>给定固定输入，所有 Rand 下的各种程序项（应）分为三类：</p>
<ul>
<li>输出是不确定的，因此永远不可重复</li>
<li>输出是确定的，但不被认为是可移植的</li>
<li>输出是确定的，被认为是可移植的</li>
</ul>
<p>一般来说，函数被认为是确定的和可移植的，<em>除非</em>它显然是非确定性的（例如<code>getrandom</code> 和 <code>ThreadRng</code>）<em>或者</em>它被特别标记为不可移植的（例如<code>StdRng</code>，<code>SmallRng</code>）。</p>
<h2><a class="header" href="#crate-versions" id="crate-versions">Crate versions</a></h2>
<h2><a class="header" href="#crate-的版本" id="crate-的版本">Crate 的版本</a></h2>
<p>我们尝试遵循<a href="https://docs.npmjs.com/misc/semver">语义化版本规则(semver rules)</a>中关于API的 <code>MAJOR.MINOR.PATCH</code>形式的版本管理规则：</p>
<ul>
<li>新的 *补丁(patch)*版本不应包括破坏API的更改或新增主要的新特性</li>
<li>在1.0版本之前，*小(minor)*版本可能包含破坏API的更改。1.0之后就不应该了。</li>
</ul>
<p>此外，我们还必须考虑<em>突破性变化</em>和<em>可移植性</em>。当给定固定输入时，</p>
<ul>
<li>对于非确定性程序项，实现可以在任何版本中更改</li>
<li>对于确定性的不可移植的程序项，在补丁(patch)版本中应该保留与原版本相同的输出，但在任何小(minor)版本中（包括1.0之后）可能会发生变化。</li>
<li>对于可移植性程序项，在跨越版本时出现对输出的任何更改都被视为等同于破坏API的更改。</li>
</ul>
<h3><a class="header" href="#testing" id="testing">Testing</a></h3>
<h3><a class="header" href="#测试" id="测试">测试</a></h3>
<p>如果可能的话，我们希望所有的伪随机算法都能检验其输出的值的稳定性：</p>
<ul>
<li>PRNG应与提供的参考值组成的向量进行比较 (<a href="https://github.com/rust-random/rngs/blob/master/rand_xoshiro/src/xoshiro256starstar.rs#L113">example</a>)</li>
<li>其他算法应该在 <code>value_stability</code>测试或类似的测试中包含它们自己的测试向量(<a href="https://github.com/rust-random/rand/blob/master/src/distributions/bernoulli.rs#L168">example</a>)</li>
</ul>
<h2><a class="header" href="#limitations" id="limitations">Limitations</a></h2>
<h2><a class="header" href="#局限性" id="局限性">局限性</a></h2>
<h3><a class="header" href="#portability-of-usize" id="portability-of-usize">Portability of usize</a></h3>
<h3><a class="header" href="#usize的可移植性" id="usize的可移植性">usize的可移植性</a></h3>
<p>遗憾的是，有一个不可移植的东西被烙进了 Rust语言的核心：<code>usize</code>（和 <code>isize</code>）。例如，空 <code>Vec</code> 的大小在32位和64位目标系统上会有所不同。在大多数情况下，这不是一个问题，但当涉及到以可移植的方式生成随机数时，这确实很重要。</p>
<p>一个简单的规则如下：如果需要可移植性，<em>永远不要</em>直接依赖 <code>usize</code> 或 <code>isize</code> 来抽样。</p>
<p>在 Rand 里，只要有可能，我们都遵守这条规则。所有需要一个有界的 <code>usize</code>值的序列相关的代码都会在 <code>u32</code>值上抽样，除非值的上限超过了 <code>u32::MAX</code>。
（请注意，在许多情况下，这实际上提高了基准性能。）</p>
<h3><a class="header" href="#portability-of-floats" id="portability-of-floats">Portability of floats</a></h3>
<h3><a class="header" href="#浮点数的可移植性" id="浮点数的可移植性">浮点数的可移植性</a></h3>
<p>浮点运算的结果取决于舍入模式和实现细节。尤其是超越函数的结果会因平台而异。因此，<code>rand_nudistr</code> 中的分布并不总是可移植到 <code>f32</code> 和 <code>f64</code> 中。然而，我们将努力使它们尽可能的可移植。</p>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/update.md">update.md</a><br />
commit: 8c0b21d507951509e8aea391bbc635d7db6306de <br />
本章译文最后维护日期：2020-12-1</p>
</blockquote>
<h1><a class="header" href="#updating" id="updating">Updating</a></h1>
<h1><a class="header" href="#升级" id="升级">升级</a></h1>
<p>本指南旨在帮助升级到 Rand的下一个小版本或主版本。注意，升级到下一个补丁版本（例如0.5.1到0.5.2）应该永远不需要修改代码。</p>
<p>这个指南提供了比 <a href="https://github.com/rust-random/rand/blob/master/CHANGELOG.md">changelog</a> 更多的细节，特别是提供了关于如何使用新特性以及如何从旧版本中迁移的指导。</p>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/update-0.5.md">update-0.5.md</a><br />
commit: c8fce4fed283853aa4ff237ba969763c059a81d1 <br />
本章译文最后维护日期：2020-12-1</p>
</blockquote>
<h1><a class="header" href="#updating-to-05" id="updating-to-05">Updating to 0.5</a></h1>
<h1><a class="header" href="#升级至05版" id="升级至05版">升级至0.5版</a></h1>
<p>与0.4版本相比，0.5版本有相当大的变化；因此，阅读下面关于破坏性/突破性变更的报道是值得的。这个版本还包含了许多优化，限于篇幅问题，下面并没有详细说明。</p>
<h2><a class="header" href="#crates" id="crates">Crates</a></h2>
<p>我们有了一个新的 crate：<code>rand_core</code>！这个 crate 包含了一些重要的 trait，即 <code>RngCore</code>、<code>BlockRngCore</code>、<code>SeedableRng</code> 和 <code>CryptoRng</code>，错误(<code>Error</code>)类型，以及两个实现辅助(helper)模块：<code>le</code> 和 <code>impls</code>。建议生成器的实现使用 <code>rand_core</code> crate，而其他用户仅使用 <code>rand</code> crate就可以了，该 crate 重新导出了 <code>rand_core</code> 的大部分内容。</p>
<p><code>rand_derive</code> crate 由于 <code>Rand</code> 的使用率很低而被弃用。</p>
<h2><a class="header" href="#features" id="features">Features</a></h2>
<h2><a class="header" href="#特性" id="特性">特性</a></h2>
<p>此版本增加了几个新的 Cargo特性标志位：</p>
<ul>
<li><code>alloc</code>，在不需要显式开启 <code>std</code>特性标志位的情况下，允许使用 <code>Box</code> 和 <code>Vec</code></li>
<li><code>serde1</code> 被加入进来，用于支持对一些PRNG的序列化</li>
<li><code>log</code> 用于在几个地方（主要是 <code>OsRng</code> 和 <code>JitterRng</code>）记录日志</li>
</ul>
<h2><a class="header" href="#rng-and-friends-core-traits" id="rng-and-friends-core-traits"><code>Rng</code> and friends (core traits)</a></h2>
<p><code>Rng</code> trait 被分成了两个 trait，一个是“后端”的 <code>RngCore</code>（由生成器实现），另一个是“前端”的 <code>Rng</code>，它实现了所有的便捷的扩展方法。</p>
<p>生成器的实现必须改为 <code>impl RngCore</code>。鼓励使用 <code>rand_core</code> 来实现各种生成器；<code>rand_core::{le, impls}</code>这两辅助模块可能被证明是很有用的。</p>
<p><em>不需要实现</em> <code>Rng</code> 的用户不需要做太多更改；通常用户可以忘记 <code>RngCore</code>，只导入 <code>Rng</code> 就够了。用户应该选择使用 <code>Rng::gen()</code>，而不是 <code>RngCore::next_u32()</code> / <code>next_u64()</code>；使用 <code>Rng::fill(dest)</code>，而不是使用 <code>RngCore::fill_bytes(dest)</code>。</p>
<h3><a class="header" href="#rng--rngcore-methods" id="rng--rngcore-methods"><code>Rng</code> / <code>RngCore</code> methods</a></h3>
<h3><a class="header" href="#rng--rngcore-方法" id="rng--rngcore-方法"><code>Rng</code> / <code>RngCore</code> 方法</a></h3>
<p>为了允许为易出错的源（例如 <code>OsRng</code>）进行错误处理，为此添加了一个新的 <code>RngCore::try_fill_bytes</code>方法；例如，<code>EntropyRng</code> 使用此机制在<code>OsRng</code> 失败时返回到 <code>JitterRng</code>，并且为各种错误处理程序生成更好的错误消息。
与以前一样，其他方法在失败时依旧会触发 panic，但由于这些方法通常与算法生成器一起使用，而算法生成器通常是绝对正确的，因此这被认为是一种适当的折衷方案。</p>
<p>老版本的 <code>Rng</code> 中的一些方法已被删除或弃用，包括：</p>
<ul>
<li><code>next_f32</code> 和 <code>next_f64</code>；这些已不再由生成器实现；现在使用 <code>gen</code> 来替代</li>
<li><code>gen_iter</code>；用户可以使用带有闭包的标准迭代器：<code>::std::iter::repeat(()).map(|()| rng.gen())</code></li>
<li><code>gen_ascii_chars</code>; 像上面这行一样使用 <code>repeat</code>函数和使用 <code>rng.sample(Alphanumeric)</code> 来替代</li>
<li><code>gen_weighted_bool(n)</code>; 使用 <code>gen_bool(1.0 / n)</code> 来替代</li>
</ul>
<p><code>Rng</code> 中增加了几个新方法：</p>
<ul>
<li><code>sample(distr)</code>，此方法是各种 <code>Distribution</code> 的 <code>distr.sample(rng)</code>方法的快捷方法</li>
<li><code>gen_bool(p)</code>，此方法生成布尔值，其中有 <code>p</code> 的概率生成 true值</li>
<li><code>fill</code> 和 <code>try_fill</code>，分别对应于 <code>fill_bytes</code> 和 <code>try_fill_bytes</code>（它们唯一的区别是错误处理）；它们可以直接填充整型切片/数组，并提供比 <code>gen()</code> 更好的性能</li>
</ul>
<h3><a class="header" href="#constructing-prngs" id="constructing-prngs">Constructing PRNGs</a></h3>
<h3><a class="header" href="#构造prng" id="构造prng">构造PRNG</a></h3>
<h4><a class="header" href="#new-randomly-initialised-prngs" id="new-randomly-initialised-prngs">New randomly-initialised PRNGs</a></h4>
<h4><a class="header" href="#新建随机初始化prng" id="新建随机初始化prng">新建随机初始化PRNG</a></h4>
<p>此版本添加了一个新的 trait：<code>FromEntropy</code>。对于支持 <code>SeedableRng</code> 的任何类型，都会自动实现这个 trait，它用新鲜的强熵来构造PRNG：</p>
<pre><pre class="playground"><code class="language-rust">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use rand::{ChaChaRng, FromEntropy};

let mut rng = ChaChaRng::from_entropy();
<span class="boring">}
</span></code></pre></pre>
<h4><a class="header" href="#seeding-prngs" id="seeding-prngs">Seeding PRNGs</a></h4>
<h4><a class="header" href="#为prng置种" id="为prng置种">为PRNG置种</a></h4>
<p><code>SeedableRng</code> trait 已被修改为通过关联类型（<code>SeedableRng::Seed</code>）而不是模板参数（<code>SeedableRng&lt;Seed&gt;</code>）来包含种子类型。此外，所有PRNG现在都是从字节数组（<code>[u8；N]</code>，其中N为固定值）。这允许对PRNG的置种进行泛型处理，这在老版本中是不可能的。</p>
<p>PRNG不再通过 <code>Rand</code> 的支持/<code>gen()</code> 来从其他PRNG构建，而是通过 <code>SeedableRng::from_rng</code>，它允许错误处理，并且是有意显式的。</p>
<p><code>SeedableRng::reseed</code> 已被删除，因为它没有 <code>from_seed</code>实用，性能优势也值得怀疑。</p>
<p><code>SeedableRng</code> 的实现可能需要将它们的 <code>Seed</code>类型更改为字节数组；此限制是为了确保在字节序(endianness)不同的平台上的可移植性。<code>rand_core::le</code> 为这种更改提供的辅助函数可以从这类字节数组读取 <code>u32</code> 和 <code>u64</code>值。</p>
<h3><a class="header" href="#block-based-prngs" id="block-based-prngs">Block-based PRNGs</a></h3>
<h3><a class="header" href="#基于块的prng" id="基于块的prng">基于块的PRNG</a></h3>
<p>rand_core 有一个新的辅助trait，<code>BlockRngCore</code>，和其实现<code>BlockRng</code>。这些是由生成器来使用的，生成器每次生成一个随机数据块，而不是字大小(word-sized,译者注：和usize一样宽)的值。使用这个 trait 和实现有两个优点：提供了优化的 <code>RngCore</code> 方法，并且PRNG可以与 <code>ReseedingRng</code> 一起使用，开销非常低。</p>
<h3><a class="header" href="#cryptographic-rngs" id="cryptographic-rngs">Cryptographic RNGs</a></h3>
<h3><a class="header" href="#加密型rng" id="加密型rng">加密型RNG</a></h3>
<p>增加了一个新trait：<code>CryptoRng</code>。这是一个纯标记trait，用来表明哪些生成器是加密型的，例如 <code>fn foo&lt;R: Rng + CryptoRng&gt;(rng: &amp;mut R)</code>。<em>注意，此trait无法保证加密使用的适用性。</em></p>
<h2><a class="header" href="#error-handling-1" id="error-handling-1">Error handling</a></h2>
<h2><a class="header" href="#错误处理-1" id="错误处理-1">错误处理</a></h2>
<p>添加了一个新的 <code>Error</code>类型，它明确设计为兼容 no-std模式，足够简单，并且有足够的适应性供我们使用（尽可能携带<code>cause</code>属性）：</p>
<pre><pre class="playground"><code class="language-rust">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>pub struct Error {
    pub kind: ErrorKind,
    pub msg: &amp;'static str,
    // 一些忽略的字段
}
<span class="boring">}
</span></code></pre></pre>
<p>关联的 <code>ErrorKind</code> 允许将错误分为永久的、意外的、暂时的和尚未准备好的这几种。</p>
<p>下述函数使用这个新的错误类型：</p>
<ul>
<li><code>RngCore::try_fill_bytes</code></li>
<li><code>Rng::try_fill</code></li>
<li><code>OsRng::new</code></li>
<li><code>JitterRng::new</code></li>
</ul>
<h2><a class="header" href="#external-generators" id="external-generators">External generators</a></h2>
<h2><a class="header" href="#外部生成器" id="外部生成器">外部生成器</a></h2>
<p>此版本增加了一个新的生成器 <code>EntropyRng</code>，它包装了 <code>OsRng</code> 和 <code>JitterRng</code>（它倾向于使用前者，但在必要时可以使用后者）。这样就可以通过 <code>SeedableRng::from_rng</code> 轻松构造带应急(fallback)功能的生成器，例如 <code>IsaacRng::from_rng(EntropyRng::new())?</code>。 除了错误处理外，这相当于使用 <code>FromEntropy</code>。</p>
<p>推荐使用 <code>EntropyRng</code>，而不是 <code>OsRng</code>，以避免在系统生成器损坏的平台上出现错误，但应该注意的是 <code>JitterRng</code> 的应急切换非常缓慢。</p>
<h2><a class="header" href="#prngs" id="prngs">PRNGs</a></h2>
<h2><a class="header" href="#伪随机数生成器" id="伪随机数生成器">伪随机数生成器</a></h2>
<p><em>伪随机数生成器</em>（即确定性算法生成器）自0.4版以来发生了一些变化，现在它们被封装在 <code>prng</code>模块中（为了兼容，旧名称暂时可用；但最终这些生成器可能会被放置在 <code>rand</code> crate）。</p>
<p>所有PRNG现在均不实现 <code>Copy</code> 以防止意外复制生成器的状态（从而重复生成值）。通过 <code>Clone</code> 来显式克隆仍然可用。所有PRNG现在都有一个 <code>Debug</code> 的自定义实现，但它不打印任何内部状态；这有助于避免在日志文件中意外泄漏加密生成器状态。建议外部PRNG实现遵循此模式（另请参见 <code>RngCore</code> 的相关文档）。</p>
<p><code>SmallRng</code> 已经被添加为包装器，目前是围绕 <code>XorShiftRng</code>（但可能很快被另一种算法取代）。这适用于小状态，快速初始化很重要，但不需要加密强度的情况。（生成的实际性能因基准(benchmark)不同而有所不同；根据使用情况，这可能是或可能不是最快的算法，但速度很快是肯定的。）</p>
<h3><a class="header" href="#reseedingrng" id="reseedingrng"><code>ReseedingRng</code></a></h3>
<p>为了减少开销，<code>ReseedingRng</code>包装器已被显著更改。不幸的是，新的 <code>ReseedingRng</code> 并不与所有RNG兼容，只兼容那些使用 <code>BlockRngCore</code> 的RNG。</p>
<h3><a class="header" href="#chacha" id="chacha">ChaCha</a></h3>
<p><code>ChaChaRng::set_counter</code>方法已被两个新方法 <code>set_word_pos</code> 和 <code>set_stream</code> 替换。如有必要，旧方法的表现可模拟如下：</p>
<pre><pre class="playground"><code class="language-rust">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">use rand::prelude::*;
</span><span class="boring">use rand_chacha::ChaChaRng;
</span>let lower = 88293;
let higher = 9300932;

// 之前:
// let mut rng = rand::ChaChaRng::new_unseeded();
// rng.set_counter(lower, higher);

// 现在:
let mut rng = ChaChaRng::from_seed([0u8; 32]);
rng.set_word_pos(lower &lt;&lt; 4);
rng.set_stream(higher);

assert_eq!(4060232610, rng.next_u32());
assert_eq!(2786236710, rng.next_u32());
<span class="boring">}
</span></code></pre></pre>
<h3><a class="header" href="#isaac-prngs" id="isaac-prngs">ISAAC PRNGs</a></h3>
<p><code>IsaacRng</code> 和 <code>Isaac64Rng</code> PRNG现在有了一个附加的构造方法：<code>new_from_u64(seed)</code>。64位的状态对于加密来说是不够的，但可以在模拟和游戏中使用。这在将来很可能会被任何从哈希对象构造的PRNG的方法所取代。</p>
<h3><a class="header" href="#hc-128" id="hc-128">HC-128</a></h3>
<p>这是一个新的加密型生成器，被评选为“适合广泛采用的流密码”之一。现在这是默认的加密生成器，<code>StdRng</code> 和 <code>thread_rng()</code> 都可使用它。</p>
<h2><a class="header" href="#helper-functionstraits" id="helper-functionstraits">Helper functions/traits</a></h2>
<h2><a class="header" href="#辅助函数trait" id="辅助函数trait">辅助函数/trait</a></h2>
<p><code>Rand</code> trait 已被弃用。相反，鼓励用户使用 <code>Standard</code>，这是一个真实的分布，支持与 <code>Rand</code> 相同的抽样。<code>Rng::gen()</code> 现在使用 <code>Standard</code>，效果应该和以前一样。具体请参阅 <code>distributions</code>模块的文档，了解如何使用用户类型<code>T</code> 来为 <code>Standard</code> 实现 <code>Distribution&lt;T&gt;</code>。</p>
<p><code>weak_rng()</code> 已被弃用；请改用 <code>SmallRng::from_entropy()</code>。</p>
<h2><a class="header" href="#distributions-1" id="distributions-1">Distributions</a></h2>
<h2><a class="header" href="#分布" id="分布">分布</a></h2>
<p><code>Sample</code> trait 和 <code>IndependentSample</code> trait 已被单个 trait <code>Distribution</code> 所取代。<code>Distribution</code> 在很大程度上相当于 <code>IndependentSample</code>，但是它的 <code>ind_sample</code> 只被替换为了 <code>sample</code>。对可变分布的支持已经被放弃；尽管可变分布看起来可能会有一些真正的用途，但这些用途还没有被广泛地用于可以证明两个独立的 trait 的存在必要性，或来证明有必要提供对分布对象的可变访问。<code>Sample</code> 和 <code>IndependentSample</code> 仍可用，但已被建议弃用；它们将在将来的版本中删除。</p>
<p><code>Distribution::sample</code>（以及其他几个函数）现在可以直接在非固定尺寸类型的RNG上调用。</p>
<p><code>RandSample</code> 已被移除（请参阅 <code>Rand</code>弃用和新的 <code>Standard</code>分布）。</p>
<p><code>Closed01</code>包装器已删除，但新增了 <code>OpenClosed01</code>。</p>
<h3><a class="header" href="#uniform-distributions-1" id="uniform-distributions-1">Uniform distributions</a></h3>
<h3><a class="header" href="#均匀分布-1" id="均匀分布-1">均匀分布</a></h3>
<p>有两个新的分布可用：</p>
<ul>
<li><code>Standard</code> 为许多不同的类型生成均匀分布的样本，并被作为 <code>Rand</code>的替代品</li>
<li><code>Alphanumeric</code> 从区间 <code>a-z A-Z 0-9</code> 抽样字符(<code>char</code>s)</li>
</ul>
<h4><a class="header" href="#ranges" id="ranges">Ranges</a></h4>
<h4><a class="header" href="#区间" id="区间">区间</a></h4>
<p><code>Range</code>分布已被大量修改，并更名为 <code>Uniform</code>：</p>
<ul>
<li><code>Uniform::new(low, high)</code> 保留（等效与半开区间 <code>[low, high)</code>）</li>
<li><code>Uniform::new_inclusive(low, high)</code> 加入进来, 在抽样区间中包括 <code>high</code></li>
<li><code>Uniform::sample_single(low, high, rng)</code> 是一个效率更高的变体，相比于从 <code>[low, high)</code> 进行单次抽样来说</li>
</ul>
<p><code>Uniform</code> 现在可以被用户自定义的类型所实现；具体请参见 <code>uniform</code>模块。</p>
<h3><a class="header" href="#non-uniform-distributions-1" id="non-uniform-distributions-1">Non-uniform distributions</a></h3>
<h3><a class="header" href="#非均匀分布-1" id="非均匀分布-1">非均匀分布</a></h3>
<p>两个分布被加入进来：</p>
<ul>
<li>泊松(Poisson)分布，在固定的时间间隔内（例如核衰变），对恒定速率源的预期事件数进行建模</li>
<li>二项式(Binomial)分布，模拟固定数量的是非试验的结果</li>
</ul>
<p>抽样方法基于“Numerical Recipes in C”中的方法。</p>
<h4><a class="header" href="#exponential-and-normal-distributions" id="exponential-and-normal-distributions">Exponential and Normal distributions</a></h4>
<h4><a class="header" href="#指数分布和正态分布" id="指数分布和正态分布">指数分布和正态分布</a></h4>
<p>主 <code>Exp</code>分布和 <code>Normal</code>分布没有变化，但是“standard”版本 <code>Exp1</code> 和 <code>StandardNormal</code> 不再是包装器类型，而是完整的分布了。<code>let Exp1(x) = rng.gen();</code> 的写法被替代为 <code>let x = rng.sample(Exp1);</code> 了。</p>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/update-0.6.md">update-0.6.md</a><br />
commit: 1552084912cc773ba6e528d216b0a351fe0468b4 <br />
本章译文最后维护日期：2020-12-1</p>
</blockquote>
<h1><a class="header" href="#updating-to-06" id="updating-to-06">Updating to 0.6</a></h1>
<h1><a class="header" href="#升级至06版" id="升级至06版">升级至0.6版</a></h1>
<p>在0.6版的发行周期中，Rand 在 <a href="https://github.com/rust-random">rust-random</a>项目下找到了一个新家。我们现在已经有宾至如归的感觉了，但是如果你愿意帮我们装饰，那贡献一个<a href="https://github.com/rust-random/rand/issues/278">新logo</a>我们将不胜感激！</p>
<p>我们还为以用户为中心的文档找到了一个新的家——这本书！</p>
<h2><a class="header" href="#prngs-1" id="prngs-1">PRNGs</a></h2>
<h2><a class="header" href="#伪随机数生成器-1" id="伪随机数生成器-1">伪随机数生成器</a></h2>
<p>我们<a href="https://docs.rs/rand/0.5/rand/prng/index.html">旧的PRNG模块</a>中的所有PRNG都被移到了新的 crate 中了。我们还添加了一个带有PCG算法的额外 crate，以及一个带有 Xoshiro/Xoroshiro算法的外部crate：</p>
<ul>
<li><a href="https://crates.io/crates/rand_chacha"><code>rand_chacha</code></a></li>
<li><a href="https://crates.io/crates/rand_hc"><code>rand_hc</code></a></li>
<li><a href="https://crates.io/crates/rand_isaac"><code>rand_isaac</code></a></li>
<li><a href="https://crates.io/crates/rand_xorshift"><code>rand_xorshift</code></a></li>
<li><a href="https://crates.io/crates/rand_pcg"><code>rand_pcg</code></a></li>
<li><a href="https://crates.io/crates/xoshiro"><code>xoshiro</code></a></li>
</ul>
<h3><a class="header" href="#smallrng" id="smallrng">SmallRng</a></h3>
<p>本次更新，我们将 <a href="https://rust-random.github.io/rand/rand/rngs/struct.SmallRng.html"><code>SmallRng</code></a> 后面的算法从 Xorshift 切换到PCG算法（要么是 <a href="https://rust-random.github.io/rand/rand_pcg/type.Pcg64Mcg.html"><code>Pcg64Mcg</code></a> (也就是 XSL 128/64 MCG)，或者 <a href="https://rust-random.github.io/rand/rand_pcg/type.Pcg32.html"><code>Pcg32</code></a> (也就是 XSH RR 64/32 LCG，也就是标准PCG算法)）。</p>
<h2><a class="header" href="#sequences-1" id="sequences-1">Sequences</a></h2>
<h2><a class="header" href="#序列-1" id="序列-1">序列</a></h2>
<p><a href="https://rust-random.github.io/rand/rand/seq/index.html"><code>seq</code>模块</a>已经被完全重写了，并且 <code>choose</code>方法和 <code>shuffle</code>方法已从 <a href="../rand/trait.Rng.html"><code>Rng</code></a> trait中删除。大多数函数现在可以在 <a href="https://rust-random.github.io/rand/rand/seq/trait.IteratorRandom.html"><code>IteratorRandom</code></a> trait 和 <a href="https://rust-random.github.io/rand/rand/seq/trait.SliceRandom.html"><code>SliceRandom</code></a> trait 中找到。</p>
<h3><a class="header" href="#weighted-choices" id="weighted-choices">Weighted choices</a></h3>
<h3><a class="header" href="#加权选择" id="加权选择">加权选择</a></h3>
<p><a href="https://docs.rs/rand/0.5/rand/distributions/struct.WeightedChoice.html"><code>WeightedChoice</code></a>分布现在已被替换为 <a href="https://rust-random.github.io/rand/rand/distributions/struct.WeightedIndex.html"><code>WeightedIndex</code></a>，通过改进函数的通用性，解决了几个问题。<!-- tobocheck --></p>
<p>为了方便起见，<a href="https://rust-random.github.io/rand/rand/seq/trait.SliceRandom.html#tymethod.choose_weighted"><code>SliceRandom::choose_weighted</code></a>方法（和其 <code>_mut</code>变体）允许将 <a href="https://rust-random.github.io/rand/rand/distributions/struct.WeightedIndex.html"><code>WeightedIndex</code></a>抽样直接应用于切片。<!-- tobocheck --></p>
<h2><a class="header" href="#other-features" id="other-features">Other features</a></h2>
<h2><a class="header" href="#其他特性" id="其他特性">其他特性</a></h2>
<h3><a class="header" href="#simd-types" id="simd-types">SIMD types</a></h3>
<p>Rand 现在有了生成SIMD类型的基本支持，此功能通过 <code>simd_support</code>特性标志位来开启</p>
<h3><a class="header" href="#i128--u128-types" id="i128--u128-types"><code>i128</code> / <code>u128</code> types</a></h3>
<p>由于这些类型现在可以在稳定的编译器上使用了，所以这些类型是自动支持的（需要足够新 Rust版本）。为向前兼容 <code>i128_support</code>特性标志位仍然存在，但不再起任何作用。</p>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/update-0.7.md">update-0.7.md</a><br />
commit: 1552084912cc773ba6e528d216b0a351fe0468b4 <br />
本章译文最后维护日期：2020-12-1</p>
</blockquote>
<h1><a class="header" href="#updating-to-07" id="updating-to-07">Updating to 0.7</a></h1>
<h1><a class="header" href="#更新至07版" id="更新至07版">更新至0.7版</a></h1>
<p>自0.6版本发布以来，<a href="https://github.com/rust-random">rust-random</a> 获得了一个 logo 和一个新的 crate：<a href="https://github.com/rust-random/getrandom">getrandom</a>！</p>
<h2><a class="header" href="#dependencies" id="dependencies">Dependencies</a></h2>
<h2><a class="header" href="#依赖" id="依赖">依赖</a></h2>
<p>Rand crates 现在需要 <code>rustc</code> 1.32.0或更的高版本。
这样我们就可以移除所有的 <code>build.rs</code>文件以加快编译速度。</p>
<p>Rand crate 现在整体上依赖更少了，尽管有一些新的。</p>
<h2><a class="header" href="#getrandom-1" id="getrandom-1">Getrandom</a></h2>
<p>如前所述，我们有了一个新的 crate：<a href="https://github.com/rust-random/getrandom">getrandom</a>，它提供了一个最小的API，可以独立于平台访问新鲜熵源。这替换了 [<code>OsRng</code>] 中以前的实现，现在它只是一个包装器。</p>
<h2><a class="header" href="#core-features" id="core-features">Core features</a></h2>
<h2><a class="header" href="#核心特性" id="核心特性">核心特性</a></h2>
<p><a href="https://docs.rs/rand/0.6.0/rand/trait.FromEntropy.html"><code>FromEntropy</code></a> trait 现在已被移除。不过不用担心，它的 <a href="https://rust-random.github.io/rand/rand/trait.SeedableRng.html#method.from_entropy"><code>from_entropy</code></a>方法在其“新家” <a href="https://rust-random.github.io/rand/rand/trait.SeedableRng.html"><code>SeedableRng</code></a> trait 中继续能对外提供简单的初始化功能（这需要 <code>rand_core</code> 启用 <code>std</code>特性或 <code>getrandom</code>特性）：</p>
<pre><pre class="playground"><code class="language-rust">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use rand::{SeedableRng, rngs::StdRng};
let mut rng = StdRng::from_entropy();
<span class="boring">}
</span></code></pre></pre>
<p><a href="https://rust-random.github.io/rand/rand/trait.SeedableRng.html#method.from_rng"><code>SeedableRng::from_rng</code></a>方法现在被认为是值稳定的：实现返回的结果应该可移植。<!-- tobocheck --></p>
<p><code>rand_core</code> 和 <code>rand</code> 的 <a href="https://rust-random.github.io/rand/rand_core/struct.Error.html"><code>Error</code></a>类型的进行了重大的重新设计；直接使用这种类型可能需要做出一些调整。</p>
<h2><a class="header" href="#prngs-2" id="prngs-2">PRNGs</a></h2>
<p>与上一版本相比，这些版本的更改较少，但值得注意的是：</p>
<ul>
<li><a href="https://crates.io/crates/rand_chacha"><code>rand_chacha</code></a> 已被重写以获得更好的性能（通过SIMD指令）。</li>
<li><a href="https://rust-random.github.io/rand/rand/rngs/struct.StdRng.html"><code>StdRng</code></a> 和 <a href="https://rust-random.github.io/rand/rand/rngs/struct.ThreadRng.html"><code>ThreadRng</code></a> 现在使用了 ChaCha算法。这是 <a href="https://rust-random.github.io/rand/rand/rngs/struct.StdRng.html"><code>StdRng</code></a> 的破坏性变更(value-breaking change)。</li>
<li><a href="https://rust-random.github.io/rand/rand/rngs/struct.SmallRng.html"><code>SmallRng</code></a> 现在在 <code>small_rng</code>特性标志位后面被选通。</li>
<li><a href="https://rust-random.github.io/rand/rand/rngs/struct.SmallRng.html"><code>SmallRng</code></a> is now gated behind the <code>small_rng</code> feature flag.</li>
<li><code>xoshiro</code> crate 现在位于 <a href="https://crates.io/crates/rand_xoshiro"><code>rand_xoshiro</code></a> 下。</li>
<li><code>rand_pcg</code> 现在包含了 <a href="https://rust-random.github.io/rand/rand_pcg/type.Pcg64.html"><code>Pcg64</code></a>.</li>
</ul>
<h2><a class="header" href="#distributions-2" id="distributions-2">Distributions</a></h2>
<h2><a class="header" href="#分布-1" id="分布-1">分布</a></h2>
<p>对于最广泛使用的分布（<a href="https://rust-random.github.io/rand/rand/distributions/struct.Standard.html"><code>Standard</code></a> 和 <a href="https://rust-random.github.io/rand/rand/distributions/struct.Uniform.html"><code>Uniform</code></a>），此版本没有明显的变化。但对于其他的<em>大部分</em>来说...</p>
<ul>
<li>我们添加了一个新的 crate [rand_distr]，用于存放所有分布（包括重新导出仍在 <a href="https://rust-random.github.io/rand/rand/distributions/index.html"><code>rand::distributions</code></a> 中的分布）。如果以前使用的是 <a href="https://rust-random.github.io/rand/rand/distributions/struct.Normal.html"><code>rand::distributions::Normal</code></a>，那么现在应该使用 <a href="https://rust-random.github.io/rand/rand_distr/struct.Normal.html"><code>rand_distr::Normal</code></a>。</li>
<li>许多分布的构造函数都进行了更改，以便于返回 <code>Result</code>，而不是碰到出错就直接 panic 了事。</li>
<li>现在许多分布在其参数上已经实现了泛型化（在大多数情况下支持 <code>f32</code> 和 <code>f64</code>）。这有助于使用泛型代码，并可以减小那些参数化的分布的尺寸。目前比较复杂的算法总是在内部使用 <code>f64</code>。</li>
<li><a href="https://rust-random.github.io/rand/rand/distributions/struct.Standard.html"><code>Standard</code></a> 现在可以抽样 <a href="https://doc.rust-lang.org/std/num/index.html"><code>NonZeroU*</code></a> 数字了。</li>
</ul>
<p>我们新增了几个分布：</p>
<ul>
<li><a href="https://rust-random.github.io/rand/rand/distributions/alias_method/struct.WeightedIndex.html"><code>rand::distributions::weighted::alias_method::WeightedIndex</code></a></li>
<li><a href="https://rust-random.github.io/rand/rand_distr/struct.Pert.html"><code>rand_distr::Pert</code></a></li>
<li><a href="https://rust-random.github.io/rand/rand_distr/struct.Triangular.html"><code>rand_distr::Triangular</code></a></li>
<li><a href="https://rust-random.github.io/rand/rand_distr/struct.UnitBall.html"><code>rand_distr::UnitBall</code></a></li>
<li><a href="https://rust-random.github.io/rand/rand_distr/struct.UnitDisc.html"><code>rand_distr::UnitDisc</code></a></li>
<li><a href="https://rust-random.github.io/rand/rand_distr/struct.UnitSphere.html"><code>rand_distr::UnitSphere</code></a>（之前被称为 <code>rand::distributions::UnitSphereSurface</code>）</li>
</ul>
<h2><a class="header" href="#sequences-2" id="sequences-2">Sequences</a></h2>
<h2><a class="header" href="#序列-2" id="序列-2">序列</a></h2>
<p>为了便于移植，当上限小于 <code>u32::MAX</code> 时，所有类型为 <code>usize</code> 的随机样本都将在内部被转换为对 <code>u32</code>类型的值进行抽样。这意味着升级到0.7版对于使用<code>seq</code>函数来说是一个破坏性变更，但是在升级到0.7版之后，抽样结果应该在跨CPU架构中保持一致。</p>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/contributing.md">contributing.md</a><br />
commit: 6737301cf36ec1bf312ce193a60fe6651e9f8eb3 <br />
本章译文最后维护日期：2020-12-2</p>
</blockquote>
<h1><a class="header" href="#contributing" id="contributing">Contributing</a></h1>
<h1><a class="header" href="#贡献" id="贡献">贡献</a></h1>
<p>感谢您对为 Rand 做贡献感兴趣！</p>
<p>我们对所有贡献者开放，但请考虑到我们的资源有限，通常在项目中有其他正在进行的工作，而且即使接受完整的PR也会花费我们的时间（审查和潜在的持续支持），因此我们可能需要相当长的时间来回复您。</p>
<h2><a class="header" href="#all-contributions" id="all-contributions">All contributions</a></h2>
<h2><a class="header" href="#所有的贡献" id="所有的贡献">所有的贡献</a></h2>
<ul>
<li>
<p>**范围(Scope)：**请考虑您的“issue”是否属于本项目的现有范围，或只是一种改进。请注意，是否将某物视为“缺陷”可能取决于您的观点。我们可以选择拒绝贡献，以避免增加我们的工作量。</p>
<p>如果您希望扩展本项目的范围（例如，新的平台或额外的CI测试），请准备提供持续的支持。</p>
</li>
<li>
<p>**修改(Fixes)：**如果你自己可以很容易地解决这个问题，请考虑提交一个PR，而不是打开一个问题。另一方面，如果不太容易解决的问题或者看起来与其他工作有冲突，不要犹豫，直接开启一个 issue。</p>
</li>
</ul>
<h2><a class="header" href="#pull-requests" id="pull-requests">Pull Requests</a></h2>
<h2><a class="header" href="#合并请求" id="合并请求">合并请求</a></h2>
<ul>
<li>
<p><strong>更新日志(Changelog):</strong> 除非你的改动非常小，否则请在每个受影响的 crate 的更改日志(<code>CHANGELOG.md</code>)中，在顶部的 <code>[Unreleased]</code> 标题下（如有必要添加）添加一个注释。请包括PR编号（这意味着必须在提请PR<em>之后</em>必须增加这么一条备注）。</p>
</li>
<li>
<p><strong>提交(Commits):</strong> 如果做出了较大的更改，可以考虑在多个提交上拆分这些更改，如果可能的话，每个这样的提交至少都可以编译通过。当做出重大更改时，变基(Rebasing commits)提交可能更合适。</p>
</li>
<li>
<p><strong>文档(Documentation):</strong> 我们需要所有的公用程序项(items)都配备相应的文档。适当的时候，还可以包括简短的例子。</p>
</li>
<li>
<p><strong>可维护性(Maintainability):</strong> 对我们来说，代码易于阅读和理解，并且方便检查其正确性是很重要的。</p>
</li>
<li>
<p><strong>性能(Performance):</strong> 我们总是以良好的性能为目标，有时会做相当多的额外工作来达到这一目标，然而，我们还必须为可维护性做出妥协，并考虑是否值得为提高效率而增加额外的代码复杂度。<a href="contrib-bench.html">使用基准</a></p>
</li>
<li>
<p><strong>风格(Style):</strong> 代码整洁干净。<em>通常</em>每行长度限制为80个字符。</p>
</li>
<li>
<p><strong>非安全关键字(unsafe):</strong> 在必要的时候使用它，而不是在有好的选择的时候使用它。确保 <code>unsafe</code>代码易于检查其正确性。</p>
</li>
<li>
<p><strong>许可和属性(License and attribution):</strong> 这个项目在MIT和Apache公共许可证v2版下是自由许可的。我们假定所有的捐款都是在这些许可证拨款下作出的。版权由贡献者保留。</p>
<p>我们的工作归功于“Rand项目开发者”。这不是一个正式的实体，只是这个项目的所有贡献者的集合。更多信息，请参见<a href="COPYRIGHT">COPYRIGHT</a>文件。</p>
</li>
<li>
<p><strong>谢谢！</strong></p>
</li>
</ul>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/contrib-doc.md">contrib-doc.md</a><br />
commit: 3edaf6ff2d931b366c3f8dd1bae5cf523aa9672c <br />
本章译文最后维护日期：2020-12-2</p>
</blockquote>
<h1><a class="header" href="#documentation" id="documentation">Documentation</a></h1>
<h1><a class="header" href="#文档" id="文档">文档</a></h1>
<h3><a class="header" href="#style" id="style">Style</a></h3>
<h3><a class="header" href="#风格" id="风格">风格</a></h3>
<p>所有的文档都是英文的，并且最好没有特定的方言。</p>
<p>这些文档应该可以被多种受众访问：既有经验丰富的 Rustaceans，也有相对的新手，有统计建模或密码学方面的资深人士，也有对这门学科不熟悉的人。
因为通常不可能写出适合所有人的文档，所以我们更喜欢参考简洁的技术文档，而不是针对特定读者的扩展文章。</p>
<h2><a class="header" href="#api-documentation" id="api-documentation">API documentation</a></h2>
<h2><a class="header" href="#api文档" id="api文档">API文档</a></h2>
<h3><a class="header" href="#rand-crates" id="rand-crates">Rand crates</a></h3>
<p>建议使用 nightly Rust 来正确处理各种超链接。</p>
<p>要为 <a href="https://github.com/rust-random/rand">rust-random/rand</a> 代码库中的所有 crate 构建完整的API文档，请执行：</p>
<pre><code class="language-sh"># 为所有模块构建文档：
cargo doc --all --no-deps

# 打开文档链接
xdg-open target/doc/rand/index.html
</code></pre>
<p>在Linux上，很容易设置在做出任何编辑后自动重新构建：</p>
<pre><code class="language-sh">while inotifywait -r -e close_write src/ rand_*/; do cargo doc; done
</code></pre>
<p>编辑完API文档后，我们推荐测试了一些示例，并检查一下是否有坏链接：</p>
<pre><code class="language-sh">cargo test --doc

cargo install cargo-deadlinks
# 建议先把之前编译的剩余文件删除
rm -rf /target/doc
cargo doc --all --no-deps
cargo deadlinks --dir target/doc
</code></pre>
<p>Rand API文档被自动构建并托管在 <a href="../rand">rust-random.github.io/rand</a> 下。获取最新的代码可在 master 分支下获取。</p>
<h3><a class="header" href="#getrandom-crate" id="getrandom-crate">Getrandom crate</a></h3>
<p><a href="https://github.com/rust-random/getrandom">rust-random/getrandom</a> 代码库只包含了一个 crate，因此一个简单的 <code>cargo doc</code>命令就行了。</p>
<h3><a class="header" href="#cross-crate-links" id="cross-crate-links">Cross-crate links</a></h3>
<p>当链接另一个 crate 时，我们更喜欢链接到 crates.io 上的相应的 crate页面。因为(a)这里有记录板条箱用途的 README文件，(b)这些链接能直接链接到相应的代码库和API文档。示例：</p>
<pre><pre class="playground"><code class="language-rust">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 链接到相应的 crate页面:：
//! [`rand_chacha`]: https://crates.io/crates/rand_chacha
<span class="boring">}
</span></code></pre></pre>
<p>当需要链接参考另一 crate 里的某个程序项时，</p>
<ol>
<li>如果该项可以通过 crate 依赖项（即使不是通过公共API）访问到时，则使用 Rust程序路径</li>
<li>当链接到 <code>rust-random/rand</code>代码库中的另一个 crate 时，可以使用生成的文档文件（<code>target/doc</code>下）中的相对路径；这些在 <a href="../rand">rust-random.github.io/rand</a> 上可行，但当前在 <code>docs.rs</code>网址下不行（参见<a href="https://github.com/rust-lang/docs.rs/issues/204">docs#204</a>）</li>
<li>如果以上两种都不适用，请使用绝对链接</li>
<li>考虑修改文件，例如以链接到 crate 来代替</li>
</ol>
<p>示例：</p>
<pre><code>// 我们依赖 rand_core，因此可以使用 Rust的路径：
/// [`BlockRngCore`]: rand_core::block::BlockRngCore

// rand_chacha不是一个依赖项，但在同一个代码库中：
//! [`ChaCha20Rng`]: ../../rand_chacha/struct.ChaCha20Rng.html

// 直接链接到 docs.rs，注意带上主版本号和小版本号，但补丁版本号不需要：
https://docs.rs/getrandom/0.1/getrandom/fn.getrandom.html
</code></pre>
<h2><a class="header" href="#auxilliary-documentation" id="auxilliary-documentation">Auxilliary documentation</a></h2>
<h2><a class="header" href="#辅助文档" id="辅助文档">辅助文档</a></h2>
<h3><a class="header" href="#readme-files" id="readme-files">README files</a></h3>
<h3><a class="header" href="#readme文件" id="readme文件">README文件</a></h3>
<p>README文件包含了对当前crate、盾牌徽章(shield badges)、有用链接、特性标志位的相关文档、许可证信息和潜在的示例的简要介绍。</p>
<p>在大多数情况下，本项目的文件没有任何持续的测试。在包含示例的地方（目前只针对 <code>rand_jitter</code> crate），我们通过 <code>doc_comment</code> 启用了持续测试（请参见 <a href="https://github.com/rust-random/rand/blob/master/rand_jitter/src/lib.rs#L62">lib.rs:62 onwards</a>）。</p>
<h3><a class="header" href="#changelog-files" id="changelog-files">CHANGELOG files</a></h3>
<h3><a class="header" href="#更新日志changelog文件" id="更新日志changelog文件">更新日志(CHANGELOG)文件</a></h3>
<p>更新日志的格式同 <a href="http://keepachangelog.com/en/1.0.0/">Keep a Changelog</a> 的格式要求保持一致。</p>
<p>自上次发布以来合并的所有重大更改都应该列在日志顶部的 <code>[Unreleased]</code>段落下面。</p>
<h3><a class="header" href="#the-book" id="the-book">The book</a></h3>
<h3><a class="header" href="#关于本书" id="关于本书">关于本书</a></h3>
<p>本书的源代码包含在 <a href="https://github.com/rust-random/book">rust-random/book</a>代码库中。它是使用 mdbook 构建的，这使得构建和测试都很容易：</p>
<pre><code class="language-sh">cargo install mdbook --version &quot;^0.2&quot;

mdbook build --open
mdbook test

# 任何更改后都自动重新构建：
mdbook watch
</code></pre>
<p>请注意，书中的链接是相对的，并且这些链接都被预先设定用于<a href="../book/">已发布上线的版本</a>。如果您在本地构建本书，您可能需要设置一个符号链接，以指向您构建的API文档：</p>
<pre><code class="language-sh">ln -s ../rand/target/doc rand
</code></pre>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/contrib-doc.md">contrib-doc.md</a><br />
commit: 3edaf6ff2d931b366c3f8dd1bae5cf523aa9672c <br />
本章译文最后维护日期：2020-12-2</p>
</blockquote>
<h1><a class="header" href="#scope" id="scope">Scope</a></h1>
<h1><a class="header" href="#覆盖范围" id="覆盖范围">覆盖范围</a></h1>
<p>随着时间的推移，本项目的覆盖范围已经扩大，Rand 已经从使用单一 crate 成长为使用一个“主”crate 加上多个单一用途的 crate 了。对于那些新功能，必须考虑把它放在哪里合适，它是否适合 Rand项目。</p>
<p>体积小的，聚焦的 crate 可能会因为一些原因被使用，但是我们的目标<em>不是</em>将功能最大程度地划分为体积小的 crate。为一个功能就使用一个单独的 crate 的理由如下：</p>
<ul>
<li>使依赖关系层次结构（<code>rand_core</code>）更清晰</li>
<li>使该功能能以独立的方式可用（例如 <code>getrandom</code>）</li>
<li>为常用的 crate 瘦身；从广泛使用的 crate 中删除很少使用的功能（例如，<code>rand_jitter</code> 和 <code>rand_distr</code> 都是从 <code>rand</code> 中提取的功能） <!-- tobocheck --></li>
<li>允许用户自行选择，避免让所有的用户导入大量不会使用的代码，这样客户端也不会产生大量的新 crate （RNG家族的crate，如 <code>rand_xoshiro</code> 和<code>rand_isaac</code>）<!-- tobocheck --></li>
</ul>
<h2><a class="header" href="#traits-basics-and-ui" id="traits-basics-and-ui">Traits, basics and UI</a></h2>
<p>Rand项目的主用户界面仍然以 <code>rand</code> crate 为中心。这个 crate 的目标是：</p>
<ul>
<li>方便使用</li>
<li>在单一位置暴露常用函数</li>
<li>允许使用额外的随机源和分布采样器</li>
</ul>
<p>为了实现更好的模块化，核心trait 已被移动到 <code>rand_core</code> crate 中了。这个 crate 的目标是:</p>
<ul>
<li>用最小的依赖暴露核心 trait</li>
<li>提供实现各种随机源所需的通用工具</li>
</ul>
<h2><a class="header" href="#external-random-sources" id="external-random-sources">External random sources</a></h2>
<h2><a class="header" href="#外部随机源" id="外部随机源">外部随机源</a></h2>
<p>随机性的主要（通常也是唯一的）外部来源是操作系统，我们通过 <code>getrandom</code> crate 和这些外部源进行交互。此 crate 还支持在一些 <code>no_std</code>目标上使用RDRAND。</p>
<p>对其他 <code>no_std</code>目标的支持已经讨论过了，但还没有多少真正的实现结果。请参看 <a href="https://github.com/rust-random/getrandom/issues/4">getrandom#4</a>。</p>
<p><code>rand_jitter</code> crate 提供了一个基于<a href="http://www.chronox.de/jent.html">CPU抖动(Jitter)</a>技术实现的熵收获器，由于历史原因，它只包含在 Rand 中。</p>
<p><code>rand_os</code> crate 提供了一个对 <code>getrandom</code> 的 <code>RngCore</code>实现。</p>
<h2><a class="header" href="#pseudo-random-generators" id="pseudo-random-generators">Pseudo-random generators</a></h2>
<h2><a class="header" href="#伪随机生成器" id="伪随机生成器">伪随机生成器</a></h2>
<p>Rand库包括几个伪随机数生成器，原因如下：</p>
<ul>
<li>实现 <code>StdRng</code>生成器和 <code>SmallRng</code>生成器</li>
<li>提供一些高质量的可选生成器</li>
<li>历史版本中已经在使用了</li>
</ul>
<p>有一些生成器是在它们自己“家族”的 crate 里实现的，比如：<code>rand_chacha</code>、<code>rand_pcg</code>、<code>rand_xoshiro</code>。</p>
<p>我们已经收到了几个要求采用新的算法的请求；在评估这类请求能否真正入库时，我们必须考虑几件事:</p>
<ul>
<li>纳入 Rand 的目的</li>
<li>PRNG是否加密安全，如果是，其声明有多可信</li>
<li>统计输出评价等级</li>
<li>生成器的性能和特性</li>
<li>接收和让第三方来审核算法</li>
</ul>
<h2><a class="header" href="#distributions-3" id="distributions-3">Distributions</a></h2>
<h2><a class="header" href="#分布-2" id="分布-2">分布</a></h2>
<p><code>Distribution</code> trait 是由 Rand 提供的，Rand 同时也提供了那些常用的分布（大多是线性分布）。</p>
<p>另外的分布被打包在 <code>rand_distr</code> crate 中，它依赖 <code>rand</code>，并重新导出它所有的分布。</p>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/contrib-test.md">contrib-test.md</a><br />
commit: adc83513424faad20dd73319b63438bfe23f6a25 <br />
本章译文最后维护日期：2020-12-2</p>
</blockquote>
<h1><a class="header" href="#testing-1" id="testing-1">Testing</a></h1>
<h1><a class="header" href="#测试-1" id="测试-1">测试</a></h1>
<p>Rand 中有许多单元测试，尽管这些都不是全面或完美的（欢迎改进）。我们更欢迎对所有新功能进行测试。</p>
<p>第一行测试是简单地从适当的目录运行 <code>cargo test</code>。因为 Rand 支持 <code>no_std</code>（仅标准库的核心(core)库可用）、<code>core+alloc</code> 和 <code>std</code> 三种环境，所以对这三个环境进行测试是很重要的（取决于哪些特性适用于相关代码）：<!-- tobocheck --></p>
<pre><code class="language-sh"># 使用 std环境进行测试：
cargo test
# 只是用 core库进行测试:
cargo test --tests --no-default-features
# 使用 core + alloc 环境进行测试 (需要在 Rust 的 nightly 版本下):
cargo +nightly test --tests --no-default-features --features=alloc
</code></pre>
<p>当然也值得使用其他特性标志位进行测试：</p>
<pre><code class="language-sh">cargo test --all-features
</code></pre>
<p>注意，这只测试当前包（即从存储库的顶层执行测试时，测试的是 Rand库的主分支）。要测试其它库，请先 <code>cd</code> 到它的目录中。</p>
<p>我们不建议使用 Cargo的 <code>--package</code>选项，因为它与 <code>--feature</code>选项一起使用时会出现<a href="https://github.com/rust-lang/cargo/issues/5364">出人意料的的交互效果</a>使，并且当同一包的多个版本位于构建树中时会失败。CI会替代使用<code>--manifest-path</code> 来选择包；在开发时，使用 <code>cd</code> 会更容易地避免此问题。</p>
<h2><a class="header" href="#writing-tests" id="writing-tests">Writing tests</a></h2>
<h2><a class="header" href="#编写测试" id="编写测试">编写测试</a></h2>
<p>测试可以是 <code>test</code>模块中的单元测试、文档示例测试、示例应用程序测试（<code>examples</code>目录）、集成测试（<code>tests</code>目录）或基准测试（<code>benches</code>目录）。</p>
<p>请注意，<em>只有</em>单元测试和集成测试预期能通过 <code>no_std</code>（仅限核心库）和 <code>core+alloc</code>配置的测试。这是一个经过深思熟虑的选择；示例代码测试应该只在普通情况（<code>std</code>）下可测。</p>
<h3><a class="header" href="#random-number-generators" id="random-number-generators">Random Number Generators</a></h3>
<h3><a class="header" href="#随机数生成器-1" id="随机数生成器-1">随机数生成器</a></h3>
<p>测试代码通常需要一些RNG来进行测试，但不需要特定的RNG。在这种情况下，我们更喜欢使用 <code>::test::rng</code>，这个生成器相对简单、初始化速度块、输出结果确定：</p>
<pre><pre class="playground"><code class="language-rust">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let mut rng = ::test::rng(528); // 仅挑选一些数字
<span class="boring">}
</span></code></pre></pre>
<p>各种测试涉及的属性<em>可能</em>是正确的，但不是绝对的。我们倾向于这样的测试是确定性的，以避免虚假的失败。<!-- tobocheck --></p>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/contrib-bench.md">contrib-bench.md</a><br />
commit: 6f247aaf15b49a09711cb5f97f2fafe1216a30e7 <br />
本章译文最后维护日期：2020-12-2</p>
</blockquote>
<h1><a class="header" href="#benchmarks" id="benchmarks">Benchmarks</a></h1>
<h1><a class="header" href="#测试基准" id="测试基准">测试基准</a></h1>
<p>我们已经有了许多测试基准：</p>
<pre><code class="language-sh">cargo +nightly bench

# In a few cases, nightly features may use different code paths:
cargo +nightly bench --features=nightly
</code></pre>
<p>分布的基准测试现在位于 <code>rand_distr</code> crate 中；所有其他基准测试（包括所有的RNG）都位于主 <code>rand</code> crate 中（因此有许多开发环境的依赖包）。</p>
<p>Rand 中的许多代码都是性能敏感的，其中大部分代码预计将用于某些库/应用程序的热循环中。如果在 <code>rand_core</code>、PRNG crate 或 <code>rngs</code>和 <code>distributions</code>模块中更改代码（尤其是在 'obvious cleanup' 时），请确保基准测试不会倒退。</p>
<p>请报告任何受影响基准的前后结果。如果您正在优化以前没有基准的东西，请首先添加新的基准，然后在单独的提交中添加您的更改（以使基准测试之前和之后更容易）。</p>

                    </main>

                    <nav class="nav-wrapper" aria-label="Page navigation">
                        <!-- Mobile navigation buttons -->
                        

                        

                        <div style="clear: both"></div>
                    </nav>
                </div>
            </div>

            <nav class="nav-wide-wrapper" aria-label="Page navigation">
                

                
            </nav>

        </div>

        

        

        

        
        <script type="text/javascript">
            window.playground_copyable = true;
        </script>
        

        

        
        <script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="searcher.js" type="text/javascript" charset="utf-8"></script>
        

        <script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="highlight.js" type="text/javascript" charset="utf-8"></script>
        <script src="book.js" type="text/javascript" charset="utf-8"></script>

        <!-- Custom JS scripts -->
        

        
        
        <script type="text/javascript">
        window.addEventListener('load', function() {
            window.setTimeout(window.print, 100);
        });
        </script>
        
        

    </body>
</html>
